【问题标题】:How to set CheckBox.IsChecked based on existence of bound object in a List如何根据列表中绑定对象的存在设置 CheckBox.IsChecked
【发布时间】:2011-06-20 11:01:38
【问题描述】:

有 2 个列表 - AvailableItems 和 SelectedItems。

AvailableItems 显示在一个 ListBox 中,每个 ListBoxItem 都包含一个 CheckBox。目的是如果绑定的项目在 SelectedItems 中,则检查 CheckBox。

我可以在不处理代码隐藏中的 Checked 和 Unchecked 并且不向我的项目类添加 IsSelected 属性的情况下实现此目的吗?

这是目前的 XAML:

   <ListBox Name="ListBox1" ItemsSource="{Binding Path=AvailableItems}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel></StackPanel>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <DockPanel>
                    <CheckBox Name="cb1"></CheckBox>
                    <TextBlock Text="{Binding}"></TextBlock>
                </DockPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ListBox>

和代码隐藏:

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            _availableItems.Add(Colors.Red);
            _availableItems.Add(Colors.Green);
            _availableItems.Add(Colors.Blue);

            _selectedItems.Add(Colors.Green);

            this.DataContext = this;
        }

        ObservableCollection<Color> _selectedItems = new ObservableCollection<Color>();
        public ObservableCollection<Color> SelectedItems
        {
            get { return _selectedItems; }
            set { _selectedItems = value; }
        }

        ObservableCollection<Color> _availableItems = new ObservableCollection<Color>();
        public ObservableCollection<Color> AvailableItems
        {
            get { return _availableItems; }
            set { _availableItems = value; }
        }
    }

上面的xaml/code可以直接复制到新的WPF项目中进行测试。

【问题讨论】:

    标签: .net wpf data-binding checkbox observablecollection


    【解决方案1】:

    使用 MVVM 的粗略模型

    创建一个类来表示每个项目所需的所有数据,例如 Checked 和 description

    class CustomItem : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
    
            private bool _isSelected;
            private string _customColour;
    
            public bool IsSelected
            {
                get { return _isSelected; }
                set 
                { 
                    _isSelected = value;
                    if (PropertyChanged != null)
                    {
                        PropertyChanged.Invoke(this, new PropertyChangedEventArgs("IsSelected"));
                    }
                }
            }
    
            public string CustomColour
            {
                get { return _customColour; }
                set
                {
                    _customColour = value;
                    if (PropertyChanged != null)
                    {
                        PropertyChanged.Invoke(this, new PropertyChangedEventArgs("CustomColour"));
                    }
                }
            }        
        }
    

    创建一个类来表示您要显示的项目集合

       class CustomItems : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
            private ObservableCollection<CustomItem> _listOfCustomItems;
    
            public CustomItems()
            {
                ListOfCustomItems = new ObservableCollection<CustomItem>();
    
                var c = new CustomItem
                            {
                                IsSelected = false, 
                                CustomColour = "Red"
                            };
                ListOfCustomItems.Add(c); 
    
                c = new CustomItem
                        {
                            IsSelected = true, 
                            CustomColour = "Green"
                        };
                ListOfCustomItems.Add(c);
    
                c = new CustomItem
                        {
                            IsSelected = false, 
                            CustomColour = "Blue"
                        };
    
                ListOfCustomItems.Add(c);
            }
    
            public ObservableCollection<CustomItem> ListOfCustomItems
            {
                get { return _listOfCustomItems; }
                set 
                { 
                    _listOfCustomItems = value;
                    if (PropertyChanged != null)
                    {
                        PropertyChanged.Invoke(this, new PropertyChangedEventArgs("ListOfCustomItems"));
                    }
                }
            }
    
            public List<CustomItem> SelectedItems
            {
                get
                {
                    return (from customItem in ListOfCustomItems 
                            where customItem.IsSelected 
                            select customItem).ToList();
                }
            }
        }
    

    添加到窗口

     <Window.Resources>
            <WpfApplication1:CustomItems x:Key="CI"/>
        </Window.Resources>
        <Grid DataContext="{StaticResource CI}">
            <ListBox ItemsSource="{Binding Path=ListOfCustomItems}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel></StackPanel>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <DockPanel>
                            <CheckBox IsChecked="{Binding Path=IsSelected}"/>
                            <TextBlock Text="{Binding Path=CustomColour}"/>
                        </DockPanel>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ListBox>
        </Grid>
    

    您维护一个项目列表,并提供一个属性来获取执行简单 LINQ 选择的选定项目。简单。根据需要更改数据类型。

    【讨论】:

    • 谢谢,但问题很清楚 - without adding an IsSelected property to my item class
    【解决方案2】:

    你定义了一个多值转换器,它接受一个项目和一个集合并返回一个布尔值:

    public class CollectionContainsConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            var item = values[0];
            var collection = values[1] as IList;
            return collection.Contains(item);
        }
    
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    

    然后你像这样使用它:

        <ListBox Name="ListBox1" ItemsSource="{Binding Path=AvailableItems}">
            <ListBox.Resources>
                <local:CollectionContainsConverter x:Key="contains"/>
            </ListBox.Resources>
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel></StackPanel>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <DockPanel>
                        <CheckBox Name="cb1">
                            <CheckBox.IsChecked>
                                <MultiBinding Converter="{StaticResource contains}" Mode="OneWay">
                                    <Binding Mode="OneWay"/>
                                    <Binding ElementName="ListBox1" Path="DataContext.SelectedItems" Mode="OneWay"/>
                                </MultiBinding>
                            </CheckBox.IsChecked>
                        </CheckBox>
                        <TextBlock Text="{Binding}"></TextBlock>
                    </DockPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ListBox>
    

    处理反向转换留作练习。

    【讨论】:

      猜你喜欢
      • 2010-11-04
      • 1970-01-01
      • 2021-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多