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

如何过滤ObservableCollection中已用盘符绑定DataGridView并保留变更通知

解决方案

1. 现有代码BUG修正

首先纠正NetworkDrive类的属性通知错误:Name、IsLetterAvailable属性的SetAndNotify方法第三个参数错误传入了nameof(Letter),会导致这两个属性变更时无法发送正确的通知,UI无法响应变更,修改为对应属性名即可:

public class NetworkDrive : BaseNotify
{
    private char letter;
    public char Letter
    {
        get => letter;
        set => SetAndNotify(ref letter, value, nameof(Letter));
    }

    private string name;
    public string Name
    {
        get => name;
        // 修正属性名参数
        set => SetAndNotify(ref name, value, nameof(Name));
    }

    private bool isLetterAvailable;
    public bool IsLetterAvailable
    {
        get => isLetterAvailable;
        // 修正属性名参数
        set => SetAndNotify(ref isLetterAvailable, value, nameof(IsLetterAvailable));
    }
}

2. 实现动态过滤的已用盘符集合

使用WPF原生ICollectionView作为绑定源即可解决过滤后丢失变更通知的问题,它是集合的视图层,支持过滤、排序、分组能力,不会修改原集合,且可以手动触发刷新同步项属性变更:

public class EditDriveViewModel : Screen
{
    public ObservableCollection<NetworkDrive> NetworkDrives { get; } = new();
    // 对外暴露的过滤后视图,直接绑定到DataGridView的ItemsSource
    public ICollectionView UsedNetworkDrivesView { get; }

    public EditDriveViewModel()
    {
        // 初始化视图,绑定原集合为数据源
        UsedNetworkDrivesView = CollectionViewSource.GetDefaultView(NetworkDrives);
        // 设置过滤规则:仅显示IsLetterAvailable为false的已用盘符
        UsedNetworkDrivesView.Filter = item => 
        {
            return item is NetworkDrive drive && !drive.IsLetterAvailable;
        };

        // 为所有预加载的盘符订阅属性变更事件,IsLetterAvailable变更时刷新视图
        foreach (var drive in NetworkDrives)
        {
            SubscribeDrivePropertyChanged(drive);
        }

        // 若运行时会动态增减NetworkDrives集合项,监听集合变更同步订阅/取消订阅事件,避免内存泄漏
        NetworkDrives.CollectionChanged += (s, e) =>
        {
            if (e.NewItems != null)
            {
                foreach (NetworkDrive newDrive in e.NewItems)
                {
                    SubscribeDrivePropertyChanged(newDrive);
                }
            }
            if (e.OldItems != null)
            {
                foreach (NetworkDrive oldDrive in e.OldItems)
                {
                    UnsubscribeDrivePropertyChanged(oldDrive);
                }
            }
        };
    }

    private void SubscribeDrivePropertyChanged(NetworkDrive drive)
    {
        drive.PropertyChanged += (s, e) =>
        {
            if (e.PropertyName == nameof(NetworkDrive.IsLetterAvailable))
            {
                UsedNetworkDrivesView.Refresh();
            }
        };
    }

    private void UnsubscribeDrivePropertyChanged(NetworkDrive drive)
    {
        drive.PropertyChanged -= (s, e) =>
        {
            if (e.PropertyName == nameof(NetworkDrive.IsLetterAvailable))
            {
                UsedNetworkDrivesView.Refresh();
            }
        };
    }
}

3. ComboBox已用盘符标红+禁止选择

WPF场景

直接给ComboBox的项容器添加样式触发器即可,示例XAML如下:

<ComboBox ItemsSource="{Binding NetworkDrives}" DisplayMemberPath="Letter">
    <ComboBox.ItemContainerStyle>
        <Style TargetType="ComboBoxItem">
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsLetterAvailable}" Value="False">
                    <!-- 禁止选择 -->
                    <Setter Property="IsEnabled" Value="False"/>
                    <!-- 标红 -->
                    <Setter Property="Foreground" Value="Red"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ComboBox.ItemContainerStyle>
</ComboBox>

WinForms场景

处理DataGridView的两个事件即可:

  • 监听CellFormatting事件:判断当前单元格绑定的盘符IsLetterAvailable为false时,设置单元格Style.ForeColor为红色
  • 监听EditingControlShowing事件:拿到下拉编辑控件后,遍历所有项,将IsLetterAvailable为false的项设置为不可选

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 21:36:04