【问题标题】:Wpf MVVM ComboBox with Checkboxes and Select all Checkbox带有复选框的 Wpf MVVM 组合框并选择所有复选框
【发布时间】:2018-10-19 09:07:56
【问题描述】:

我有一个带有复选框的组合框,我想实现全选选项。 我在 XAML 中通过以下方式执行此操作:

<ComboBox Text="Select Industry"  TextSearch.TextPath ="Industry"  Name="industry"  IsEditable="True" IsReadOnly="True" >
    <ComboBox.ItemsSource>
        <CompositeCollection>
            <ComboBoxItem>
                <CheckBox x:Name="allIndustry">All</CheckBox>
            </ComboBoxItem>
            <CollectionContainer Collection="{Binding Source={StaticResource industrySource}}"/>
        </CompositeCollection>
    </ComboBox.ItemsSource>
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <CheckBox Name="industry" IsChecked="{Binding ElementName=allIndustry, Path=IsChecked, Mode=OneWay}" Content="{Binding Industry}" />
            </StackPanel>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

我使用上面的代码在视图中获得了这个功能:

但是,这里的问题是我曾经绑定 ViewModel 属性 IsChecked 的 IsChecked ComboBox 属性,并实现了这个解决方案,我失去了这个功能。

我想换行

IsChecked="{Binding ElementName=allIndustry, Path=IsChecked, Mode=OneWay}"

进入

<ComboBoxItem>
<CheckBox x:Name="allIndustry">All</CheckBox>
</ComboBoxItem>

将绑定更改为 OneWayToSource,并从 x:Name="allIndustry" 更新 我在 CheckBox 中选择的项目。

我应该只能从 XAML 视图中执行此操作...

之后我只需将我的 ComboBox 绑定到 ViewModel 属性...

看起来像这样:

<ComboBox Text="Select Industry"  TextSearch.TextPath ="Industry"  Name="industry"  IsEditable="True" IsReadOnly="True" >
    <ComboBox.ItemsSource>
        <CompositeCollection>
            <ComboBoxItem>
                <CheckBox x:Name="allIndustry" IsChecked="{Binding ElementName=industry, Path=IsChecked, Mode=OneWayToSource}">All</CheckBox>
            </ComboBoxItem>
            <CollectionContainer Collection="{Binding Source={StaticResource industrySource}}"/>
        </CompositeCollection>
    </ComboBox.ItemsSource>
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <CheckBox Name="industry" IsChecked="{Binding IsChecked}" Content="{Binding Industry}" />
            </StackPanel>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

但是当我实现此更改时,单击“全选”不会更新我的 ComboBox 项:

这是 ViewModel 的属性

 private ObservableCollection<IndustryFilter> _industryFilters;
        public ObservableCollection<IndustryFilter> IndustryFilters
        {
            get { return _industryFilters; }
            set
            {
                _industryFilters = value;
                PropertyChanged(this, new PropertyChangedEventArgs("IndustryFilters"));
            }
        }

这是在 XAML 视图上部定义的 Source

<UserControl x:Class="Digital_Data_House_Bulk_Mailer.View.MailView"
             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" 
             xmlns:local="clr-namespace:Digital_Data_House_Bulk_Mailer.View"
             xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
             xmlns:model="clr-namespace:Digital_Data_House_Bulk_Mailer.ViewModel"
             mc:Ignorable="d" 
             HorizontalAlignment="Stretch"
             VerticalAlignment="Stretch"
             HorizontalContentAlignment="Stretch"
             VerticalContentAlignment="Stretch"
             >
    <UserControl.Resources>

        <CollectionViewSource x:Key="industrySource" Source="{Binding IndustryFilters}"/>

    </UserControl.Resources>

我如何设法从 ComboBox.Item 源更新所有名为“行业”的组合框并将“行业”复选框绑定到 ViewModel? 问候

【问题讨论】:

    标签: c# wpf xaml mvvm combobox


    【解决方案1】:

    没有完整的工作示例很难给出完整的工作示例。

    您可以使用其他方法解决您的问题。

    您的IndustryFilters 不应该是ObservableCollection&lt;IndustryFilter&gt;,而是这样的对象的实例:

    public class IndustryFilters : INotifyPropertyChanged {
        private _isAllChecked;
    
        public IsAllChecked {
            get {return _isAllChecked;}
            set{
                _isAllChecked = value;
    
                foreach(var filter in Filters) { 
                    filter.IsChecked = value;
                }
    
                PropertyChanged(...);
            }
        }
    
        public ObservableCollection<IndustryFilter> Filters
        {
            get { return _industryFilters; }
            set
            {
                _industryFilters = value;
                PropertyChanged(this, new propertyChangedEventArgs("IndustryFilters"));
            }
        }
    }
    

    然后将&lt;CheckBox x:Name="allIndustry"&gt;All&lt;/CheckBox&gt;IsChecked 绑定到IsAllChecked 属性。

    然后你必须想办法将你的 ComboBox 的来源更改为 IndustryFilters.Filters。

    希望这会有所帮助。

    【讨论】:

    • 过滤器的更新是这样的,但复选框本身没有更新,尽管我已经放了
    • 我现在想知道,如果我设置了正确的绑定,为什么 CheckBox 没有更新?
    • 您的 IndustryFilter 是否实现了 INotifyPropertyChanged?
    • 是的,我已经用你的想法解决了这个问题......谢谢!
    【解决方案2】:

    在 bruno.almeida 的帮助下,我设法解决了这个问题

    这是 State 过滤器的 ViewModel 属性定义 - 与我询问的 Industry 字段相同:

    private ObservableCollection<StateFilter> _stateFilters;
            public ObservableCollection<StateFilter> StateFilters
            {
                get { return _stateFilters; }
                set
                {
                    _stateFilters = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("StateFilters"));
                }
            }
    
            private bool _stateFilter;
            public bool StateFilter
            {
                get { return _stateFilter; }
                set
                {
                    _stateFilter = value;
    
                    ObservableCollection<StateFilter> local = new ObservableCollection<StateFilter>();
    
                    foreach (var filter in StateFilters)
                    {
                        filter.IsChecked = _stateFilter;
                        local.Add(filter);
    
                    }
                    StateFilters = local;
    
                    PropertyChanged(this, new PropertyChangedEventArgs("StateFilter"));
    
                }
            }
    

    这是 XAML 代码示例:

    资源:

    组合框:

    <ComboBox Text="Select State"  TextSearch.TextPath ="State"  Name="state"  IsEditable="True" IsReadOnly="True" >
    
        <ComboBox.ItemsSource>
            <CompositeCollection>
                <ComboBoxItem >
                    <CheckBox  Name="all" IsChecked="{Binding StateFilter}">All</CheckBox>
                </ComboBoxItem>
                <CollectionContainer Collection="{Binding Source={StaticResource stateSource}}"/>
            </CompositeCollection>
        </ComboBox.ItemsSource>
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <CheckBox Name="chkTask" IsChecked="{Binding IsChecked}"  Content="{Binding State}" ></CheckBox>
            </DataTemplate>
    </ComboBox.ItemTemplate>
    </ComboBox>
    

    【讨论】:

    • 如果你的 StateFilter 实现了 INotifyPropertyChanged,你就不需要局部变量了。
    • 是的,我确实有 INotifyPropertyChanged,但是当我只更改列表中对象的属性 IsChecked 时,问题看起来我在 ObervableList 上的设置器没有设置...我以为我是也许要覆盖 Equals 方法但是......我看到我已经得到了结果,因为我是 WPF 的新手 - 对于这样一个微不足道的任务(我更喜欢 Web 开发),这个 Select All 功能很痛苦......跨度>
    • 在引入局部变量 a 之前使用的是这个:foreach (var filter in StateFilters) { StateFilters .IsChecked = _stateFilter; } ,但 setter 没有被调用
    • 你误会了。你有 ObservableCollection。 ObservableCollection 实现 INotifyPropertyChanged。但是,根据您的描述,StateFilter 对象本身似乎没有实现 INotifyPropertyChanged。
    • 是的,你是对的,它是一个从 db 对象派生的普通 EntityFramework 类
    猜你喜欢
    • 1970-01-01
    • 2013-09-30
    • 2013-06-15
    • 1970-01-01
    • 1970-01-01
    • 2011-09-24
    • 2014-10-14
    • 1970-01-01
    • 2016-09-01
    相关资源
    最近更新 更多