Wpf CheckedListbox - 如何获取选定的项目

8

我用以下代码在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中的项目时,它从未被触发。

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

谢谢

5个回答

10

将您的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>

您可能是点击了复选框或方块控件中的实际文本块,这不会触发列表框的选择更改。如果您尝试单击矩形边界之外的空白区域,则会触发更改。
如果您只想要作为数据模板的复选框,则需要做更多工作,因为您需要根据复选框的IsChecked属性选择/取消选择listboxitem。因此,请将其包装在ListBoxItem中,然后您就可以使用了。

该解决方案仅在您单击项目/复选框上的“特殊”位置时才有效。 - user1005448
但是当我点击复选框时,什么也不会发生。我必须点击复选框左侧才能选择一个项目并“触发”绑定。 - user1005448
我测试了解决方案,当我点击复选框/文本/空格时,它会选择该项。 - 123 456 789 0
如果您在SelectedSection属性的setter中设置断点,那么当您在列表中选择一个项目时,它会触发吗?由于某种原因,我的断点没有被命中。 - user1005448
是的,在发布答案之前,我测试了解决方案。 - 123 456 789 0

8

这是我的解决方案(基于上面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方法效果不好)!在这种情况下,当复选框被选中时,ListBoxItem被选中,反之亦然。此时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>();
}

注意:
如果您想从后端代码更改复选框集合(或选定项),并在UI中反映更改,则必须实现INotifyPropertyChanged,并在集合(或选定项)更改时通知(即当对象被重新创建时)。


2

我认为更好的解决方案是不在ListboxItem中声明,因为鼠标悬停时选择会显示在复选框上。

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

0

我绑定了一个Dictionary<string, MyEnum>,但是上面的解决方案都没有起作用。受到有关带有选中项的ListView的问题的启发,我想出了以下的解决方案,看起来像是我们所希望的 - 包括能够从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>

0
我发现以下解决方案可行:
<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中拥有的内容。我只是将其明确化,以便您可以理解,如果您不熟悉数据绑定的话。 - 123 456 789 0
我的解决方案也不太好用。当我从数据库获取部分内容并想在某些项目上设置IsChecked = true时,它的状态在视图模型中是正确的,但在UI中没有反映出来。 - user1005448

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接