Home > Back-end >  Relay Commands Command Parameter
Relay Commands Command Parameter

Time:12-15

I am trying to work with the MVVM principles within a small WPF project using C#. I have a ListBox that is populated with CheckBoxes created through binding back to the ViewModel. I also have a command bound to the CheckBoxes and wish to pass the CheckBoxes Content as a CommandParameter. I was looking for something like this:

<Binding ElementName="" Path="Content"/>

Unfortunately, because the CheckBoxes are created through a binding I don’t have the element name.

The code for ListBox / ListBoxItem Style is this:

<Style x:Key="CheckBoxListStyle" TargetType="{x:Type ListBox}">
    <Setter Property="SelectionMode" Value="Multiple"></Setter>
    <Setter Property="ItemContainerStyle">
        <Setter.Value>
            <Style TargetType="{x:Type ListBoxItem}" >
                <Setter Property="Margin" Value="2" />
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ListBoxItem}">
                            <CheckBox Command="{Binding SelectedItemCommand, Mode=OneWay, Source={StaticResource comd}}">
                                <CheckBox.CommandParameter>
                                    <MultiBinding Converter="{StaticResource cv}">
                                        <Binding ElementName="" Path="Content"/>
                                    <Binding ElementName="" Path="IsChecked"/>
                                    </MultiBinding>
                                </CheckBox.CommandParameter>
                                <ContentPresenter></ContentPresenter>
                            </CheckBox>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Setter.Value>
    </Setter>
</Style>

And its implementation is:

<ListBox Grid.Row="1" Style="{StaticResource CheckBoxListStyle}" Name="lstProducts" ItemsSource="{Binding stampInfo, Mode=OneWay, Source={StaticResource vmStamp}}" 
        DisplayMemberPath="Country" >
</ListBox>

Ultimately my goal is to be able to display the text Contents (Countries in this case) of all the selected items in a text box were each country is separated by a comma. The only thing I am currently missing is the Country.

CodePudding user response:

Do not create a ControlTemplate for ListBoxItem when you really want to display your data items differently, use a DataTemplate instead, that is exactly its purpose. See Data Templating Overview.

Remove the DisplayMemberPath from the ListBox, as you cannot use both use a path and a custom DataTemplate at the same time. You would only set this path, if there was no DataTemplate, but you wanted to specify a concrete property or property path to display.

<ListBox Grid.Row="1"
         Style="{StaticResource CheckBoxListStyle}" Name="lstProducts"
         ItemsSource="{Binding stampInfo, Mode=OneWay, Source={StaticResource vmStamp}}"/>

Replace the ControlTemplate with a DataTemplate as ItemTemplate. Then bind the Content and CommandParameter to the property Country. The data context is automatically set to the corresponding item in the bound collection of data items. The IsChecked property can be bound using a RelativeSource, which is the CheckBox itself.

<Style x:Key="CheckBoxListStyle" TargetType="{x:Type ListBox}">
   <Setter Property="SelectionMode" Value="Multiple"></Setter>
   <Setter Property="ItemContainerStyle">
      <Setter.Value>
         <Style TargetType="{x:Type ListBoxItem}" >
            <Setter Property="Margin" Value="2" />
         </Style>
      </Setter.Value>
   </Setter>
   <Setter Property="ItemTemplate">
      <Setter.Value>
         <DataTemplate>
            <CheckBox Content="{Binding Country}"
                      Command="{Binding SelectedItemCommand, Mode=OneWay, Source={StaticResource comd}}">
                <CheckBox.CommandParameter>
                    <MultiBinding Converter="{StaticResource cv}">
                        <Binding Path="Country"/>
                        <Binding Path="IsChecked" RelativeSource="{RelativeSource Self}"/>
                    </MultiBinding>
                </CheckBox.CommandParameter>
            </CheckBox>
         </DataTemplate>
      </Setter.Value>
   </Setter>
</Style>

A different option would be to create data items with a property that can be bound to the IsChecked property of CheckBox. Then you could act in the setter of the data item or on e.g. a button click that executes a command, which filters the bound collection in your view model for checked items.

  • Related