【问题标题】:Wpf CheckedListbox - how to get selected itemWpf CheckedListbox - 如何获取所选项目
【发布时间】:2014-01-17 18:31:02
【问题描述】:

我使用以下代码在 xaml 中创建了 CheckedListbox:

                    <ListBox Height="340" ItemsSource="{Binding Sections}" SelectedItem="{Binding SelectedSection}">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <CheckBox IsChecked="{Binding IsChecked}" Content="{Binding Path=Item}" />
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>

它绑定到这个集合:

public ObservableCollection<CheckedListItem<String>> Sections { get; set; }
private CheckedListItem<String> _selectedSection;
public CheckedListItem<String> SelectedSection
    {
        get { return _selectedSection; }
        set 
        {
            _selectedSection = value; 
            RaisePropertyChanged("SelectedSection"); 
        }
    }

CheckedListItem 类如下所示:

    public class CheckedListItem<T> : INotifyPropertyChanged
    {
    public event PropertyChangedEventHandler PropertyChanged;

    private bool isChecked;
    private T item;

    public CheckedListItem()
    { }

    public CheckedListItem(T item, bool isChecked = false)
    {
        this.item = item;
        this.isChecked = isChecked;
    }

    public T Item
    {
        get { return item; }
        set
        {
            item = value;
            if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Item"));
        }
    }


    public bool IsChecked
    {
        get { return isChecked; }
        set
        {
            isChecked = value;
            if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("IsChecked"));
        }
    }
}

我尝试在 _selectedSection = value 中设置断点;部分代码,但当我选择/取消选择 CheckedListBox 中的项目时,它永远不会被触发。

我的问题是如何在每次选择/取消选择时获取所选项目?

谢谢

【问题讨论】:

    标签: c# wpf xaml


    【解决方案1】:

    将您的 XAML 更改为

    <ListBox Height="340" ItemsSource="{Binding Sections}" SelectedItem="{Binding SelectedSection}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <ListBoxItem IsSelected="{Binding IsChecked}">
                    <CheckBox IsChecked="{Binding IsChecked}" Content="{Binding Path=Item}" />
                </ListBoxItem>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    

    您可能正在单击checkbox 内的实际textblock 控件或不会触发selectionchangedsquare 控件listbox。如果您尝试在矩形边界之外单击,请说出whitespace,那么它将触发。

    如果您只想将checkbox 作为数据模板,因为您想根据checkbox IsChecked 属性选择/取消选择listboxitem',这将是更多的工作。因此,只需将其包裹在 ListBoxItem 中,您就可以开始使用了。

    【讨论】:

    • 该解决方案仅在您单击项目/复选框上的“特殊”位置时才有效
    • 但是当我点击复选框时没有任何反应。我必须单击左侧的复选框以使其选择一个项目并“触发”绑定。
    • 我测试了解决方案,我点击复选框/文本/空格来选择项目。
    • 如果您在 SelectedSection 属性的设置器中设置断点,当您选择列表中的项目时会触发吗?由于某种原因,我的断点没有被命中。
    • 是的,我在发布答案之前测试了解决方案。
    【解决方案2】:

    我的解决方案(基于上述Suplanuslll解决方案):

    <ListBox ItemsSource="{Binding Checkboxes}" SelectionMode="Multiple">
        <ListBox.ItemContainerStyle>
            <Style TargetType="ListBoxItem">
                <Setter Property="IsSelected" Value="{Binding Checked, Mode=TwoWay}" />
            </Style>
        </ListBox.ItemContainerStyle>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <CheckBox IsChecked="{Binding Checked, Mode=TwoWay}" Content="{Binding Label}"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    

    我设置了 ListBoxItem IsSelected 属性通过样式(因为标准的 lll's 方式效果不佳)!在这种情况下,当 CheckBox 被选中时,ListBoxItem 被选中,反之亦然。在这种情况下,SelectionMode 也很有效。您可以在 Single SelectionMode 中添加 SelectedItem(或类似属性)

    <!-- xaml -->
    SelectedItem="{Binding SelectedCheckbox}" SelectionMode="Single"
    // cs
    public CheckboxData SelectedCheckbox { get; set; }
    

    或者甚至更好,直接在后面的代码(例如您的 ViewModel)中使用 ItemsSource(在这种情况下为 Checkboxes 集合)。

    背后的代码(例如):

    public partial class MainWindow : Window
    {
        public class CheckboxData
        {
            public int Id { get; set; }
            public string Label { get; set; }
            public bool Checked { get; set; }
        }
    
        public MainWindow()
        {
            DataContext = this;
            for (int i = 0; i < 50; i++)
                Checkboxes.Add(new CheckboxData { Id = i, Label = $"Checkbox {i}" });
        }
    
        public IList<CheckboxData> Checkboxes { get; set; } = new List<CheckboxData>();
    }
    

    注意:
    如果您想从代码后面更改 Checkboxes 集合(或选定项)(并反映 UI 中的更改),您必须实现 INotifyPropertyChanged 并在集合(或选定项)已更改时通知(字面意思是,当对象已重新创建)。

    【讨论】:

      【解决方案3】:

      我认为更好的解决方案是不在 ListboxItem 中声明,因为 Hover 上的选择显示在 Checkbox 上。

       <ListBox ItemsSource="{Binding Customers}" >
              <ListBox.ItemTemplate>
                  <DataTemplate>
                      <CheckBox IsChecked="{Binding IsChecked}" Content="{Binding Path=Item.Name}" /> 
                  </DataTemplate>
              </ListBox.ItemTemplate>
          </ListBox> 
      

      【讨论】:

        【解决方案4】:

        我找到了以下可行的解决方案:

        <ListBox Height="340" ItemsSource="{Binding Sections}" SelectedItem="{Binding SelectedSection}">
                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                    <CheckBox Content="{Binding Path=Item}" IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}"/>
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                        </ListBox>
        

        【讨论】:

        • 从技术上讲,RelativeSource 所拥有的就是我在 DataTemplate 中所拥有的。我只是把它说清楚了,以便您在不熟悉 DataBinding 的情况下可以理解。
        • 我的解决方案也不能很好地工作。当我从数据库中获取部分并希望在某些项目上设置 IsChecked = true 时,它​​的状态在视图模型中是正确的,但不会反映在 UI 中。
        【解决方案5】:

        我绑定到 Dictionary 并且上述解决方案均无效。从a question about ListView with checked items 得到启发,我能够想出以下内容,这似乎就像人们希望的那样 - 包括能够从 lstMyEnumTypes.SelectedItems 中获取选定的项目。

        <ListBox x:Name="lstMyEnumTypes" Grid.Row="1" MinHeight="100" VerticalAlignment="Stretch" ItemsSource="{Binding MyEnumsDict}"
          SelectedValuePath="Value" SelectionMode="Multiple">
          <ListBox.ItemTemplate>
            <DataTemplate>
              <CheckBox IsChecked="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}, Path=IsSelected}"
                Content="{Binding Path=Key}"/>
            </DataTemplate>
          </ListBox.ItemTemplate>
        </ListBox>
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-08-29
          • 2011-08-02
          • 1970-01-01
          • 2016-11-20
          • 1970-01-01
          • 1970-01-01
          • 2021-12-22
          • 1970-01-01
          相关资源
          最近更新 更多