Binding/Triggering “Select all”-CheckBox ComboBoxItem in WPF

老子叫甜甜 提交于 2019-12-23 04:43:53

问题


I'm trying to make a WPF CustomControl CheckComboBox with a "Select All" item in addition to a user defined list of items. When "Select All" is selected, all items in the list should be checked accordingly. How can I act to the "Select All" item being clicked? I have tried a lot of things, but the property "SelectAll" in the CheckComboBox.cs is never entered.

This is my current code.

Generic.xaml

<Style TargetType="{x:Type local:CheckComboBox}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:CheckComboBox}">
                    <ComboBox SelectedItem="{TemplateBinding SelectedItem}"
                              SelectedValue="{TemplateBinding SelectedValue}"
                              SelectedValuePath="{TemplateBinding SelectedValuePath}"
                              DisplayMemberPath="{TemplateBinding DisplayMemberPath}"
                              IsTextSearchEnabled="{TemplateBinding IsTextSearchEnabled}"
                              ItemTemplate="{TemplateBinding ItemTemplate}"
                              x:Name="InnerComboBox" >

                        <ComboBox.Resources>
                            <ResourceDictionary>
                                <CheckBox x:Key="allItem" Content="All" IsChecked="{Binding SelectAll, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" />
                                <CollectionViewSource x:Key="items" Source="{Binding ComboBoxItems, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" />
                            </ResourceDictionary>
                        </ComboBox.Resources>

                        <ComboBox.ItemsSource>
                            <CompositeCollection>
                                <ComboBoxItem Content="{Binding Source={StaticResource allItem}}"/>
                                <CollectionContainer Collection="{Binding Source={StaticResource items}}" />
                            </CompositeCollection>
                        </ComboBox.ItemsSource>

                    </ComboBox>

                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="ItemTemplate">
            <Setter.Value>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <CheckBox IsChecked="{Binding IsSelected}" Content="{Binding Text}" VerticalAlignment="Center" />
                    </StackPanel>
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>

CheckComboBox.cs

   public class CheckComboBox : ComboBox
    {
        public class CheckComboBoxItem
        {
            public CheckComboBoxItem(bool isSelected, string text)
            {
                IsSelected = isSelected;
                Text = text;
            }
            public bool IsSelected { get; set; }
            public string Text { get; set; }
        }

        static CheckComboBox()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(CheckComboBox), new FrameworkPropertyMetadata(typeof(CheckComboBox)));
        }

        public static readonly DependencyProperty ComboBoxItemsProperty =
            DependencyProperty.Register("ComboBoxItems", typeof (ObservableCollection<CheckComboBoxItem>), typeof (CheckComboBox), new PropertyMetadata(default(ObservableCollection<CheckComboBoxItem>)));

        public ObservableCollection<CheckComboBoxItem> ComboBoxItems
        {
            get { return (ObservableCollection<CheckComboBoxItem>) GetValue(ComboBoxItemsProperty); }
            set { SetValue(ComboBoxItemsProperty, value); }
        }

        public static readonly DependencyProperty SelectAllProperty =
            DependencyProperty.Register("SelectAll", typeof (bool), typeof (CheckComboBox), new PropertyMetadata(default(bool)));

        public bool SelectAll
        {
            get { return (bool) GetValue(SelectAllProperty); }
            set
            {
                foreach (var item in ComboBoxItems)
                {
                    item.IsSelected = value;
                }
                SetValue(SelectAllProperty, value);
            }
        }
    }
}

Setting test data:

ObservableCollection<CheckComboBox.CheckComboBoxItem> checkComboBoxItems = new ObservableCollection<CheckComboBox.CheckComboBoxItem>();
checkComboBoxItems.Add(new CheckComboBox.CheckComboBoxItem(false, "Generation 0"));
checkComboBoxItems.Add(new CheckComboBox.CheckComboBoxItem(true, "Generation 1"));
checkComboBoxItems.Add(new CheckComboBox.CheckComboBoxItem(false, "Generation 2"));
checkComboBox1.ComboBoxItems = checkComboBoxItems;

Edit: Replaced the SelectAll DependencyProperty in CheckComboBox.cs with the following code, but OnSelectAll is not entered. The SelectAll combobox does not trigger the binding for some reason.

public static readonly DependencyProperty SelectAllProperty =
        DependencyProperty.Register("SelectAll",
                    typeof (bool),
                    typeof (CheckComboBox),
                    new FrameworkPropertyMetadata(false,
                        FrameworkPropertyMetadataOptions.AffectsRender,
                        new PropertyChangedCallback(OnSelectAll)));

private static void OnSelectAll(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    CheckComboBox checkComboBox = (CheckComboBox)d;
    foreach (var item in checkComboBox.ComboBoxItems)
    {
        item.IsSelected = (bool) e.NewValue;
    }
}

public bool SelectAll
{
    get { return (bool) GetValue(SelectAllProperty); }
    set { SetValue(SelectAllProperty, value); }
}    

回答1:


Finally figured out how to trigger the "SelectAll" property. Notice the:

<ComboBoxItem>
    <CheckBox ... />
</ComboBoxItem>

Generic.xaml

...
<ComboBox.Resources>
    <ResourceDictionary>
        <CollectionViewSource x:Key="items" Source="{Binding ItemsSource, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" />
    </ResourceDictionary>
</ComboBox.Resources>

<ComboBox.ItemsSource>
    <CompositeCollection>
        <ComboBoxItem>
            <CheckBox Content="All" IsChecked="{Binding SelectAll, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" />
        </ComboBoxItem>
        <CollectionContainer Collection="{Binding Source={StaticResource items}}" />
    </CompositeCollection>
</ComboBox.ItemsSource>
...

CheckComboBox.cs

public class CheckComboBox : ComboBox
{
    public class CheckComboBoxItem : ModelBase
    {
        public CheckComboBoxItem(bool isSelected, string text)
        {
            IsSelected = isSelected;
            Text = text;
        }

        private bool _isSelected;
        public bool IsSelected 
        { 
            get { return _isSelected; }
            set { Set(() => IsSelected, ref _isSelected, value); }
        }

        private string _text;
        public string Text 
        { 
            get { return _text; }
            set { Set(() => Text, ref _text, value); }
        }
    }

    static CheckComboBox()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(CheckComboBox), new FrameworkPropertyMetadata(typeof(CheckComboBox)));
    }

    public static readonly DependencyProperty SelectAllProperty =
        DependencyProperty.Register("SelectAll",
                                    typeof (bool),
                                    typeof (CheckComboBox),
                                    new FrameworkPropertyMetadata(false,
                                        FrameworkPropertyMetadataOptions.AffectsRender,
                                        new PropertyChangedCallback(OnSelectAll)));

    private static void OnSelectAll(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        CheckComboBox checkComboBox = (CheckComboBox)d;
        IEnumerable<CheckComboBoxItem> items = (IEnumerable<CheckComboBoxItem>) checkComboBox.ItemsSource;
        foreach (var item in items)
        {
            item.IsSelected = (bool) e.NewValue;
        }
    }

    public bool SelectAll
    {
        get { return (bool) GetValue(SelectAllProperty); }
        set { SetValue(SelectAllProperty, value); }
    }
}

Now I just have to figure out how to automatically de-select the "Select All" check box when another item is de-selected.



来源:https://stackoverflow.com/questions/13969761/binding-triggering-select-all-checkbox-comboboxitem-in-wpf

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!