简体   繁体   中英

WPF: Get a ListBoxItem as CheckBox with a Template Style to synchronize with IsSelected

I'm making a MVVM WPF application, in this application I have a ListBox with my own Privilege Items.

After ages I finally found a solution how to get selection synchronized with my ViewModel. (You also need to implement IEquatable in your item class)

Problem

Now i want to style the ListBoxItems as CheckBoxes, there are many solutions for this problem, but none that really fits my needs.

So i came up with this solution, because I can apply this style only to the ListBoxes I need, and I don't have to worry about the DisplayMemberPath or that the Items were styled as CheckBox and ListBoxItems.

View:

<ListBox Grid.Row="5" Grid.Column="1"
         ItemsSource="{Binding Privileges}"
         BehavExt:SelectedItems.Items="{Binding SelectedPrivileges}"
         SelectionMode="Multiple"
         DisplayMemberPath="Name"
         Style="{StaticResource CheckBoxListBox}"/>

Style:

<Style x:Key="CheckBoxListBox"
       TargetType="{x:Type ListBox}"
       BasedOn="{StaticResource MetroListBox}">

    <Setter Property="Margin" Value="5" />
    <Setter Property="ItemContainerStyle"
            Value="{DynamicResource CheckBoxListBoxItem}" />
</Style>

<Style x:Key="CheckBoxListBoxItem"
       TargetType="{x:Type ListBoxItem}"
       BasedOn="{StaticResource MetroListBoxItem}">

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                <CheckBox IsChecked="{TemplateBinding Property=IsSelected}">
                    <ContentPresenter />
                </CheckBox>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

ViewModel:

private ObservableCollection<Privilege> _privileges;
public ObservableCollection<Privilege> Privileges
{
    get { return _privileges; }
    set {
        _privileges = value;
        RaisePropertyChanged(() => Privileges);
    }
}

private ObservableCollection<Privilege> _selectedPrivileges;
public ObservableCollection<Privilege> SelectedPrivileges
{
    get { return _selectedPrivileges; }
    set
    {
        _selectedPrivileges = value;
        RaisePropertyChanged(() => SelectedPrivileges);
    }
}

The Problem is this line:

IsChecked="{TemplateBinding Property=IsSelected}"

It works fine, but only in one direction. When add a item to my SelectedPrivileges in the code it will be displayed as checked, but when I check this item in the GUI it won't do anything. (Without the CheckBox style it works, so it is because a TemplateBinding only works in one direction)

How do I get this to work? I though about something like a trigger, but I have no clue how to accomplish this.

I believe what you're looking for is actually pretty straightforward. You need to change the binding mode of the IsChecked property's binding, as follows:

{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsSelected, Mode=TwoWay}

That should do it.

This and basically any other WPF binding tips can be found on this excellent cheat sheet .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM