How to bind the window loaded event? - wpf

I want to bind the loaded event from my view so tha i can read some settings at the start. With some searching i made this but it does not work. what am i missing?
the view:
<UserControl x:Name="UserControlRegistratie" x:Class="Qbox_0001.Views.RegistratieView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" HorizontalContentAlignment="Left" VerticalContentAlignment="Top"
xmlns:intr="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
>
<intr:Interaction.Triggers>
<intr:EventTrigger EventName="Loaded">
<intr:InvokeCommandAction Command="{Binding Path=windowLoadedCommand}"/>
</intr:EventTrigger>
</intr:Interaction.Triggers>
<Grid x:Name="GridRegistratie">
.....
The viewmodel:
public class RegistratieViewModel
{
public RelayCommand windowLoadedCommand { get; private set; }
public RegistratieViewModel()
{
...
//commands
windowLoadedCommand = new RelayCommand(ExecuteWindowLoaded, CanExecute);
}
private bool CanExecute(object parameter)
{
return true;
}
private void ExecuteWindowLoaded(object parameter)
{
MessageBox.Show("window laden...........");
//Nothing happens
}
}

In my view i have this : (works for the other bindings)
public partial class RegistratieView : UserControl
{
public RegistratieView()
{
InitializeComponent();
DataContext = new RegistratieViewModel();
}
}

Related

input binding is not firing command wpf wvvm

i have this in MainWindow.xaml
<Window.InputBindings>
<KeyBinding Modifiers="Ctrl" Key="Delete" Command="{Binding DelAllMessages}"/>
</Window.InputBindings>
and in MainViewModel
public void DelAllMessages()
{
MessageBoxResult result = MessageBox.Show(
"Are you sure you want to delete?",
"Confirmation",
MessageBoxButton.YesNo,
MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
// todo
}
}
}
when i press ctrl+del in keyboard in window then this method does not hit.what is missing?
You need to use Commands instead of directly binding the method. One think to keep in mind is in order to have a communication between View model and View is via Properties.
Step 1:-
Create a Command Handler class and Implement ICommand as shown in the below code.
public class CommandHandler : ICommand
{
private Action<object> _action;
private bool _canExeute;
public event EventHandler CanExecuteChanged;
private bool canExeute
{
set
{
_canExeute = value;
CanExecuteChanged(this, new EventArgs());
}
}
public CommandHandler(Action<object> action, bool canExecute)
{
_action = action;
_canExeute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExeute;
}
public void Execute(object parameter)
{
_action(parameter);
}
}
Step 2:-
Use the newly created class of Command in your Window's code behind.
Create a property of ICommand and provide your DelAllMessages() as your action to that Command, so when there is Clt + Del Pressed, it calls your method.
private ICommand _KeyCommand;
public ICommand KeyCommand
{
get { return _KeyCommand ?? (_KeyCommand = new CommandHandler(obj => DelAllMessages(), true)); }
}
Step 3:-
Assign your your window class as DataContext to the windows' Xaml.
this.DataContext = this;
Check out whole class Code.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
private ICommand _KeyCommand;
public ICommand KeyCommand
{
get { return _KeyCommand ?? (_KeyCommand = new CommandHandler(obj => DelAllMessages(), true)); }
}
public void DelAllMessages()
{
MessageBoxResult result = MessageBox.Show(
"Are you sure you want to delete?",
"Confirmation",
MessageBoxButton.YesNo,
MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
// todo
}
}
}
Step 4:-
Bind the newly created Command property in Xaml.
<Window.InputBindings>
<KeyBinding Modifiers="Ctrl" Key="Delete" Command="{Binding KeyCommand}"/>
</Window.InputBindings>
Whole Xaml Code:-
<Window x:Class="WpfApp4.TriggerTest"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp4"
mc:Ignorable="d"
Title="Window1" Height="450" Width="800">
<Window.InputBindings>
<KeyBinding Modifiers="Ctrl" Key="Delete" Command="{Binding KeyCommand}"/>
</Window.InputBindings>
<Grid>
</Grid>
</Window>

How to update a text in a view on button click from another view in WPF Prism?

I'm new to Prism and I'm trying to update a text in MainWindow.xaml another view in region.
MainWindowViewModel
private string _message = "Prism";
public string Message
{
get { return _message; }
set { SetProperty(ref _message, value);}
}
MainWindow.xaml
<Window x:Class="XXXX.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
Title="{Binding Title}">
<Grid>
<StackPanel>
<TextBlock Text="{Binding Message, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" FontSize="48"></TextBlock>
<ContentControl prism:RegionManager.RegionName="ViewARegion" />
</StackPanel>
</Grid>
ViewAViewModel
public ICommand ClickCommand
{
get;
private set;
}
public ViewAViewModel()
{
ClickCommand = new DelegateCommand(ClickedMethod);
}
private void ClickedMethod()
{
MainWindowViewModel mainWindowViewModel = new MainWindowViewModel();
mainWindowViewModel.Message = "Prism View A";
}
ViewA.xaml
<UserControl x:Class="XXXX.Views.ViewA"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:XXXX.Views"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d">
<Grid>
<StackPanel>
<Button Content="Click"
Command="{Binding ClickCommand}">
</Button>
</StackPanel>
</Grid>
Now when I click the button it's working correctly I mean it's setting the Message property in MainWindowViewModel but it's not udating the View in MainWindow.xaml.
What should I do to get this working as I'm expecting to update the view on button click?
MainWindowViewModel mainWindowViewModel = new MainWindowViewModel();
mainWindowViewModel.Message = "Prism View A";
This creates a new instance of MainWindowViewModel that has nothing to do with the instance that's bound to your MainWindow. You can change properties on this new instance all day long, the real view model will not care.
You have to implement some view model to view model communication mechanism, e.g. use IEventAggregator or a shared service, so that the information ("click happened" or "message changed" or whatever) can be passed from ViewA to the MainWindow.
You could use the event aggregator to send an event from ViewAViewModel to MainWindowViewModel:
public class ViewAViewModel
{
private readonly IEventAggregator _eventAggregator;
public ViewAViewModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
ClickCommand = new DelegateCommand(ClickedMethod);
}
public ICommand ClickCommand
{
get;
private set;
}
private void ClickedMethod()
{
_eventAggregator.GetEvent<PubSubEvent<string>>().Publish("Prism View A");
}
}
public class MainWindowViewModel : BindableBase
{
public MainWindowViewModel(IEventAggregator eventAggregator)
{
eventAggregator.GetEvent<MessageSentEvent>().Subscribe(MessageReceived);
}
private void MessageReceived(string message)
{
Message = message;
}
private string _message = "Prism";
public string Message
{
get { return _message; }
set { SetProperty(ref _message, value); }
}
}
There is a complete example available on GitHub: https://github.com/PrismLibrary/Prism-Samples-Wpf/tree/master/14-UsingEventAggregator

Execute a method in another Control using MVVM

I have built a dummy UserControl that has a method in its code-behind to display a message. I have used this control in my main window and want to execute its method when I click a Button using Commands and MVVM. Is this a good design, and if not, how can I improve it? My current code looks like this:
<UserControl x:Class="ControlBining.Control1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid DataContext="{Binding RelativeSource={RelativeSource AncestorType=UserControl}}">
</Grid>
</UserControl>
public partial class Control1 : UserControl
{
public Control1()
{
InitializeComponent();
}
public void ShowMessage()
{
MessageBox.Show("Called from other control!");
}
}
<Window x:Class="ControlBining.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ControlBining"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<StackPanel Margin="0 50 0 0">
<local:Control1 Width="100"/>
<Button Width="100" Content="Show Message"/>
</StackPanel>
</Window>
public class RelayCommand : ICommand
{
private readonly Predicate<object> m_canExecute;
private readonly Action<object> m_execute;
public RelayCommand(Predicate<object> canExecute, Action<object> execute)
{
m_canExecute = canExecute;
m_execute = execute;
}
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
public bool CanExecute(object parameter)
{
return m_canExecute(parameter);
}
public void Execute(object parameter)
{
m_execute(parameter);
}
}
Currently, I have made it work using the following code, but I am not sure if this is a good design:
private void Control1_Loaded(object sender, RoutedEventArgs e)
{
ViewModel m = (ViewModel)DataContext;
m.ShowMessage += M_ShowMessage;
}
private void M_ShowMessage()
{
ShowMessage();
}
public event Action ShowMessage;
private ICommand m_showMessageCommand;
public ICommand ShowMessageCommand
{
get
{
return m_showMessageCommand ?? (m_showMessageCommand = new RelayCommand(
p => true,
p => ShowMessage?.Invoke()));
}
}
If you simply need to show a message, you should move the ShowMessage() method to the view model and use a message service to do this from the view model class.
If you really want to call some method that it only makes sense to define in the view, this can be done by implementing an interface in the view and inject the view model with this interface. For example when you invoke the command:
public interface IView
{
void ShowMessage();
}
public partial class Control1 : UserControl, IView
{
public Control1()
{
InitializeComponent();
}
public void ShowMessage()
{
MessageBox.Show("Called from other control!");
}
}
View Model:
public ICommand ShowMessageCommand
{
get
{
return m_showMessageCommand ?? (m_showMessageCommand = new RelayCommand(
p => true,
p =>
{
IView view as IView;
if (view != null)
{
//...
view.ShowMessage();
}
}));
}
}
The view model knows nothing about the view, it only knows about an interface which of course may be called something else than IView.
The other option is to use an event aggregator or a messenger to send an event or a message from the view model to the view in a lously coupled way. Please refer to this blog post for more information about this.
Neither approach break the MVVM pattern.

My static Model/Property is not binding to my UI

New to WPF.
I am trying to bind my Model to my UI. So, when the Property is changed during my User actions I want the field to update whereever it occurs on my UI.
This is my Model:
namespace WpfApplication1
{
public class model2
{
private static string myField2;
public static string MyField2
{
get { return myField2; }
set { myField2 = value; }
}
}
}
My Markup:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:model2 x:Key="mymodel"/>
</Window.Resources>
<Grid>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Source={StaticResource ResourceKey=mymodel}, Path=MyField2}"></TextBlock>
<Button Content="static test!" Click="Button_Click_1" />
</StackPanel>
</Grid>
</Window>
My code behind:
using System.Windows;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
model2.MyField2 = "static!";
}
}
}
The field on the UI does not change?
You need to notify changes to the UI so it can update with new values.
In your case you want to notify static properties of changes so you would need a static event. The problem is the INotifyPropertyChanged interface needs a member event so you won't be able to go that way.
You best shot is to implement the Singleton pattern:
namespace WpfApplication1
{
public class model2 : INotifyPropertyChanged
{
//private ctor so you need to use the Instance prop
private model2() {}
private string myField2;
public string MyField2
{
get { return myField2; }
set {
myField2 = value;
OnPropertyChanged("MyField2");
}
}
private static model2 _instance;
public static model2 Instance {
get {return _instance ?? (_instance = new model2();)}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName) {
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
And then make your property a member property and bind like this:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:model2 x:Key="mymodel"/>
</Window.Resources>
<Grid>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Source={x:Static local:model2.Instance}, Path=MyField2}"/>
<Button Content="static test!" Click="Button_Click_1" />
</StackPanel>
</Grid>
</Window>
Code behind:
using System.Windows;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
model2.Instance.MyField2 = "static!";
}
}
}
Use the Static extension to bind the TextBlocks Text Property:
<TextBlock Text="{Binding Source={Static MyModel.MyField2}, Mode=TwoWay">
But still the Property must raise the PropertyChanged event. My understanding why you use the static field is to be able to set the value from somewhere else. Have you thougt about using messages instead? Checkout the MVVM Light toolkit and the messenger. This would decouple the two components
I think that static properties are not what you want to use, from comments I can deduce that you are using only to make your program work. Below is the full working code.
App.xaml
Remove the code StartupUri="MainWindow.xaml instead we will instantiate MainWindow in code-behind to provide DataContext.
App.xaml.cs
Here we are assigning object of Model2 as Window.DataContext and then showing the window.
public partial class App : Application
{
public App()
{
Model2 model = new Model2();
MainWindow window = new MainWindow();
window.DataContext = model;
window.Show();
}
}
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
//We get hold of `DataContext` object
var model = this.DataContext as Model2;
model.MyField2 = "Hello World";
}
}
Model:
public class Model2 : INotifyPropertyChanged
{
private string _myField2;
public string MyField2
{
get { return _myField2; }
set
{
_myField2 = value;
OnPropertyChanged("MyField2");
}
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
MainWindow.xaml
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding MyField2}"></TextBlock>
<Button Content="static test!" Click="ButtonBase_OnClick" />
</StackPanel>
</Grid>
</Window>
And I checked, it works !

WPF UserControl instead of Window in ViewModel

How can I change xaml of MenuManagement from Window to UserControl?
I want to use MenuManagement inside MainWindow xaml lik this:
this.mainViewModel = new MainWindow();
this.mainViewModel.Show();
this.mainViewModel.LayoutMain.Navigate(new MenuManagement());
but I receive error:
"Additional information: '***.Views.MenuManagement' root element is not valid for navigation."
My MenuViewModel:
class MenuViewModel : ViewModelBase<IMainView>
{
public MenuViewModel()
:base(new MenuManagement())
{ //...
}}
xaml of MenuManagment
<Window x:Class="***.Views.MenuManagement"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
Title="MenuManagement" Height="720" Width="1280">
<Grid>
...
</Grid>
MenuManagement
public partial class MenuManagement : Window, IMainView
{
public MenuManagement()
{
InitializeComponent();
} }
EDIT:
Interface
public interface IView
{
object DataContext { get; set; }
void Close();
}
public interface IMainView : IView
{
void Show();
}
}
Change this:
<Window x:Class="***.Views.MenuManagement"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
Title="MenuManagement" Height="720" Width="1280">
<Grid>
...
</Grid>
to:
<UserControl x:Class="***.Views.MenuManagement"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
Title="MenuManagement" Height="720" Width="1280">
<Grid>
...
</Grid>
</UserControl>
and this:
public partial class MenuManagement : Window, IMainView
{
public MenuManagement()
{
InitializeComponent();
}
}
to:
public partial class MenuManagement : UserControl, IMainView
{
public MenuManagement()
{
InitializeComponent();
}
}

Resources