You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用MVVM模式无法通过Xceed CheckListBox获取SelectedItems

我之前也踩过Xceed CheckListBox这个SelectedItems绑定的坑,正好可以给你几个实用的解决办法:

首先得搞清楚问题根源:Xceed CheckListBox的SelectedItems是一个只读的ICollection——当用户勾选/取消勾选选项时,它只会修改这个集合的内容,而不会重新给这个集合赋值。这就是你的ViewModel属性setter始终不触发的原因,绑定系统没有给你的属性赋新值,只是在原集合里增删元素而已。

方案1:用ObservableCollection监听集合变化(最推荐)

在ViewModel里声明一个ObservableCollection<你的枚举类型>,绑定到CheckListBox的SelectedItems,然后通过监听集合的CollectionChanged事件来捕获选中项的变化,不用依赖属性setter。

ViewModel代码示例(假设你的枚举是MyEnum):

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Collections.Specialized;
using System.Linq;

public class YourViewModel : INotifyPropertyChanged
{
    // 枚举数据源:把枚举值转成泛型集合
    public IEnumerable<MyEnum> EnumOptions { get; } = Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>();

    private ObservableCollection<MyEnum> _selectedEnums;
    public ObservableCollection<MyEnum> SelectedEnums
    {
        get => _selectedEnums;
        set
        {
            if (_selectedEnums != value)
            {
                // 移除旧集合的事件监听
                if (_selectedEnums != null)
                    _selectedEnums.CollectionChanged -= OnSelectedEnumsChanged;
                
                _selectedEnums = value;
                OnPropertyChanged();
                
                // 给新集合添加监听
                if (_selectedEnums != null)
                    _selectedEnums.CollectionChanged += OnSelectedEnumsChanged;
            }
        }
    }

    public YourViewModel()
    {
        // 初始化空集合
        SelectedEnums = new ObservableCollection<MyEnum>();
    }

    private void OnSelectedEnumsChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        // 这里处理选中项变化的逻辑
        // 比如获取当前所有选中项:var currentSelected = SelectedEnums.ToList();
        Console.WriteLine($"选中项更新:当前共选中{SelectedEnums.Count}个选项");
    }

    // 实现INotifyPropertyChanged接口
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

XAML代码示例:

<!-- 记得先引入Xceed的命名空间 -->
<UserControl xmlns:xceed="http://schemas.xceed.com/wpf/xaml/toolkit">
    <xceed:CheckListBox ItemsSource="{Binding EnumOptions}"
                        SelectedItems="{Binding SelectedEnums, Mode=TwoWay}"
                        DisplayMemberPath="ToString()">
        <!-- 要是需要自定义选项样式,可以在这里写ItemTemplate -->
    </xceed:CheckListBox>
</UserControl>

方案2:用Xceed自带的SelectedItemsBinding(版本兼容的话更简洁)

部分新版本的Xceed CheckListBox提供了SelectedItemsBinding属性,专门用于双向绑定选中项集合,用法更直接:

XAML代码示例:

<xceed:CheckListBox ItemsSource="{Binding EnumOptions}"
                    SelectedItemsBinding="{Binding SelectedEnums, Mode=TwoWay}"
                    DisplayMemberPath="ToString()" />

ViewModel代码和方案1完全一致,你依然可以通过CollectionChanged监听变化,或者在需要的时候直接访问SelectedEnums集合获取当前选中项。

方案3:手动同步的附加行为(兜底方案)

如果上面两种方法都不适合你的场景,可以用WPF附加行为手动监听SelectionChanged事件,同步选中项到ViewModel:

附加行为代码:

using System.Windows;
using System.Windows.Controls;
using Xceed.Wpf.Toolkit;

public static class CheckListBoxSelectionBehavior
{
    public static readonly DependencyProperty BoundSelectedItemsProperty =
        DependencyProperty.RegisterAttached(
            "BoundSelectedItems",
            typeof(IList),
            typeof(CheckListBoxSelectionBehavior),
            new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnBoundSelectedItemsChanged));

    public static IList GetBoundSelectedItems(DependencyObject obj)
    {
        return (IList)obj.GetValue(BoundSelectedItemsProperty);
    }

    public static void SetBoundSelectedItems(DependencyObject obj, IList value)
    {
        obj.SetValue(BoundSelectedItemsProperty, value);
    }

    private static void OnBoundSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is CheckListBox checkListBox)
        {
            checkListBox.SelectionChanged -= OnCheckListBoxSelectionChanged;
            
            if (e.NewValue is IList newSelectedList)
            {
                checkListBox.SelectionChanged += OnCheckListBoxSelectionChanged;
                // 初始化选中项
                checkListBox.SelectedItems.Clear();
                foreach (var item in newSelectedList)
                {
                    checkListBox.SelectedItems.Add(item);
                }
            }
        }
    }

    private static void OnCheckListBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (sender is CheckListBox checkListBox)
        {
            var boundList = GetBoundSelectedItems(checkListBox);
            if (boundList != null)
            {
                // 同步选中项到ViewModel的集合
                boundList.Clear();
                foreach (var item in checkListBox.SelectedItems)
                {
                    boundList.Add(item);
                }
            }
        }
    }
}

XAML使用示例:

<xceed:CheckListBox ItemsSource="{Binding EnumOptions}"
                    local:CheckListBoxSelectionBehavior.BoundSelectedItems="{Binding SelectedEnums}"
                    DisplayMemberPath="ToString()" />

这个方案里,ViewModel的SelectedEnums可以是普通的List<MyEnum>或者ObservableCollection<MyEnum>,选中项变化时会自动同步。

最后几个注意点:

  • 一定要确保你的ViewModel实现了INotifyPropertyChanged接口,否则绑定不会生效。
  • 枚举作为数据源时,记得用Cast<你的枚举类型>把Enum.GetValues返回的Array转成泛型集合,避免绑定时的类型问题。
  • 确认引用的Xceed.Wpf.Toolkit程序集版本是兼容的,太旧的版本可能没有SelectedItemsBinding属性。

内容的提问来源于stack exchange,提问作者Shweta Goyal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:04:30