I am trying to work with the MVVM principles within a small WPF project using C#.
I have a ListBox
that is populated with CheckBox
es created through binding back to the ViewModel. I also have a command bound to the CheckBox
es and wish to pass the CheckBox
es Content
as a CommandParameter
. I was looking for something like this:
<Binding ElementName="" Path="Content"/>
Unfortunately, because the CheckBox
es 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 Content
s (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.