Commands are used for handling Events
in WPF while respecting the MVVM-Pattern.
A normal EventHandler
would look like this (located in Code-Behind
):
public MainWindow()
{
_dataGrid.CollectionChanged += DataGrid_CollectionChanged;
}
private void DataGrid_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
//Do what ever
}
No to do the same in MVVM we use Commands
:
<Button Command="{Binding Path=CmdStartExecution}" Content="Start" />
I recommend to use some kind of prefix (
Cmd
) for your command properties, because you will mainly need them in xaml - that way they are easier to recognize.
Since it's MVVM you want to handle that Command (For Button
"eq" Button_Click
) in your ViewModel
.
For that we basically need two things:
A simple example could look like this:
private RelayCommand _commandStart;
public ICommand CmdStartExecution
{
get
{
if(_commandStart == null)
{
_commandStart = new RelayCommand(param => Start(), param => CanStart());
}
return _commandStart;
}
}
public void Start()
{
//Do what ever
}
public bool CanStart()
{
return (DateTime.Now.DayOfWeek == DayOfWeek.Monday); //Can only click that button on mondays.
}
So what is this doing in detail:
The ICommand
is what the Control
in xaml is binding to. The RelayCommand
will route your command to an Action
(i.e call a Method
). The Null-Check just ensures that each Command
will only get initialized once (due to performance issues). If you've read the link for the RelayCommand
above you may have noticed that RelayCommand
has two overloads for it's constructor. (Action<object> execute)
and (Action<object> execute, Predicate<object> canExecute)
.
That means you can (aditionally) add a second Method
returning a bool
to tell that Control
wheather the "Event" can fire or not.
A good thing for that is that Button
s for example will be Enabled="false"
if the Method
will return false
CommandParameters
<DataGrid x:Name="TicketsDataGrid">
<DataGrid.InputBindings>
<MouseBinding Gesture="LeftDoubleClick"
Command="{Binding CmdTicketClick}"
CommandParameter="{Binding ElementName=TicketsDataGrid,
Path=SelectedItem}" />
</DataGrid.InputBindings>
<DataGrid />
In this example I want to pass the DataGrid.SelectedItem
to the Click_Command in my ViewModel.
Your Method should look like this while the ICommand implementation itself stays as above.
private RelayCommand _commandTicketClick;
public ICommand CmdTicketClick
{
get
{
if(_commandTicketClick == null)
{
_commandTicketClick = new RelayCommand(param => HandleUserClick(param));
}
return _commandTicketClick;
}
}
private void HandleUserClick(object item)
{
MyModelClass selectedItem = item as MyModelClass;
if (selectedItem != null)
{
//Do sth. with that item
}
}