I'm working on a WPF project, and I'm trying to follow the MVVM pattern. In the past I've only used DataTemplates to display information, but now I want to put a button on my template that performs an action related to the item containing the clicked button. I'm trying to figure out the best way to bind my code to my button in a way that the code knows which button was clicked.
My WindowViewModel
contains relay commands which are exposed through command properties, as well as an ObservableCollection
of `Items'.
public class WindowViewModel
{
public ICommand ChangeItemCommand { get; private set; }
public ObservableCollection<Item> Items {get;private set;}
public WindowViewModel()
{
ChangeItemCommand = new RelayCommand(new Action<object>(this.ChangeItem));
Items = new ObservableCollection<Item>();
}
public void ChangeItem(object o)
{
string key = (string)o;
//do something to the item with provided key
}
}
My ItemViewModel
contains an ItemKey
property to identify the item.
public class ItemViewModel
{
public string ItemName { get; private set; }
public string ItemKey { get; private set; }
}
My list box DataTemplate looks something like this.
<DataTemplate DataType="local:ItemViewModel">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding ItemName}"/>
<Button Command="???" CommandParameter="{Binding ItemKey}"/>
</StackPanel>
</DataTemplate>
So I'm trying to figure out the best way to bind the button command to WindowViewModel.ChangeItemCommand
of the WindowViewModel
.
One option I'm considering would be to add a command property to the ItemViewModel
which is set when instances are created by WindowViewModel
public class ItemViewModel
{
public string ItemName { get; private set; }
public string ItemKey { get; private set; }
public ICommand ChangeItemCommand{ get; private set; }
}
<Button Command="{Binding ChangeItemCommand}" CommandParameter="{Binding ItemKey}"/>
Alternatively I could bind directly to the WindowViewModel.ChangeItemCommand
property by using a RelativeSource
.
<Button
Command="{Binding Path=ChangeItemCommand,
RelativeSource={RelativeSource AncestorType={x:Type MyAppAWindow}}}"
CommandParameter="{Binding ItemKey}"/>
Note: I'm not entirely sure I did that right
So which would be recommended, or is there another better way?
The latter is the preferred one.
There are several ways and it boils down to preferences. There are a lot of MVVM Frameworks out there like MVVM-Light and Caliburn Micro that makes binding to commands way way easier compared to pure WPF CommandBindings.