7
votes

I am developing a WPF application using the MVVM design pattern. In the application I have an ItemsControl that display several Buttons (number of buttons is not constant, according the logic flow of the application). The ItemsControl is binded to LinkedList in the ViewModel. I am able to define a Command for the Buttons and I able to get the Command handler within the ViewModel only if the Command has no parameters... I need to be able to know which button has been clicked and therefore I would like to have a Command with Parameter.

How do I need to define my View ? What is the Syntax for the CommandParameter and which parameter I can used to get the Button content ? What will be the Command signature in the ViewModel ?

Please note that I am using RelayCommand from MVVM Light. The relvant code of the View is here. Thanks in advance

<UserControl x:Class="Museum.Controls.CategoriesView"
             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="130" d:DesignWidth="418">
    <UserControl.Resources>
        <DataTemplate x:Key="CategoriesButtonsTemplate">
            <Button Content="{Binding }" 
                    Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}, Path=DataContext.CategorySelectedCommand}" 
                    />
        </DataTemplate>
    </UserControl.Resources>
    <Grid ShowGridLines="True">
        <Grid.RowDefinitions>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition Height=" 40"></RowDefinition>
            <RowDefinition Height=" 40"></RowDefinition>
        </Grid.RowDefinitions>
        <Grid x:Name="SubSubjectGrid" Grid.Row="0"></Grid>
        <Grid x:Name="CategoriesGrid" Grid.Row="1">
            <ItemsControl Grid.Row="1" 
                  ItemsSource="{Binding Path=CategoriesButtons}" 
                  ItemTemplate="{StaticResource CategoriesButtonsTemplate}" >
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Horizontal"  HorizontalAlignment="Stretch"/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
            </ItemsControl>
     </Grid>
        <Grid x:Name="SelectedCategoryGrid" Grid.Row="2"></Grid>
    </Grid>  
</UserControl>
3

3 Answers

6
votes

You can simply use CommandParameter="{Binding }" like this

       <DataTemplate x:Key="CategoriesButtonsTemplate">
        <Button Content="{Binding }" 
                Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}, Path=DataContext.CategorySelectedCommand}" 
                CommandParameter="{Binding }" 
                />
    </DataTemplate>
1
votes

There is a generic RelayCommand class in MVVM Light toolkit which can handle command parameters. The non generic RelayCommand class ignores them. Here is a example:

First bind your CommandParameter property like Ahmed showed in his answer:

    <Button Content="{Binding}" 
            Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}, Path=DataContext.CategorySelectedCommand}" 
            CommandParameter="{Binding}" />

Lets say the linked list for the buttons in your viewmodel is a list of strings. Your button content and your CommandParameter are bound to one of your list items. Now create a generic RelayCommand propterty in your viewmodel:

 private RelayCommand<String> mOnClickCommand;

 public RelayCommand<String> ClickCommand
 {
     get { return mOnClickCommand; }         
 }

Instantiate it for example like this in your constructor:

 mOnClickCommand = new RelayCommand<string>(OnButtonClicked);

And finally in your method you will get the CommandParameter property as a method argument:

 private void OnButtonClicked(String _category)
 {
     Console.WriteLine(_category);
 }

Hope this is helpful.

0
votes

You can use Interactivity and Iteractions libraries. In this case your should add this to your xaml code of a button:

<Button>
  <i:Interaction.Triggers>
        <i:EventTrigger EventName="Click">
              <ei:CallMethodAction TargetObject="{Binding}" MethodName="OnClick"/>
        </i:EventTrigger>
  </i:Interaction.Triggers>
</Button>

And to viewModel:

public void OnClick(object sender, MouseEventArgs args)
{// your code }