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

为何使用Dynamic Data无法筛选WPF数据?我的代码问题出在哪?

问题描述

我希望筛选出包含字符1、2、3的数据,以下是我的WPF代码,但点击对应按钮后并未实现筛选效果,不需要的数据仍保留在ListBox中。另外我不喜欢ReactiveUI,不想将其与Dynamic Data结合使用,请问我的代码存在什么问题?

XAML代码

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <Grid VerticalAlignment="Top">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="auto"></ColumnDefinition>
                <ColumnDefinition Width="auto"></ColumnDefinition>
                <ColumnDefinition Width="auto"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Button Click="Button_Click">1</Button>
            <Button Grid.Column="1" Click="Button_Click_1">2</Button>
            <Button Grid.Column="2" Click="Button_Click_2">3</Button>
        </Grid>
        <StackPanel Grid.Row="1">
            <ListBox x:Name="LB">

            </ListBox>
        </StackPanel>
    </Grid>
</Window>

后台代码

using DynamicData.Binding;
using DynamicData;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            for (int i = 0; i <= 100; i++)
            {
                SourceList.Add(i.ToString());
            }
            SourceList.Connect().Bind(this.BindableList).Subscribe();
            LB.ItemsSource = BindableList;
        }
        private readonly SourceList<string> SourceList = new SourceList<string>();
        public IObservableCollection<string> BindableList { get; } = new ObservableCollectionExtended<string>();

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            SourceList.Connect().Filter(_ => _.Contains("1")).Bind(this.BindableList).Subscribe();
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            SourceList.Connect().Filter(_ => _.Contains("2")).Bind(this.BindableList).Subscribe();
        }

        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            SourceList.Connect().Filter(_ => _.Contains("3")).Bind(this.BindableList).Subscribe();
        }
    }
}

问题分析与修复

你的代码主要有两个问题:

  1. 多订阅冲突:初始化时已经建立了SourceList到BindableList的直接绑定订阅,每次点击按钮又会创建一个带筛选的新订阅。两个订阅同时作用于BindableList,旧订阅会持续同步所有原始数据,直接覆盖筛选后的结果,导致筛选失效。
  2. 未管理订阅生命周期:多次点击会创建大量重复订阅,不仅功能异常,还会造成内存泄漏。

修复思路

不需要每次点击都新建数据流,而是维护一个可动态更新筛选条件的单一订阅。用Subject传递筛选条件,让数据流自动响应条件变化。

修正后的后台代码

using DynamicData.Binding;
using DynamicData;
using System;
using System.Reactive.Linq;
using System.Windows;

namespace WpfApp1
{
    public partial class MainWindow : Window
    {
        private readonly SourceList<string> SourceList = new SourceList<string>();
        public IObservableCollection<string> BindableList { get; } = new ObservableCollectionExtended<string>();
        private IDisposable _dataSubscription;
        private readonly Subject<string> _filterTrigger = new Subject<string>();

        public MainWindow()
        {
            InitializeComponent();

            // 填充初始数据
            for (int i = 0; i <= 100; i++)
            {
                SourceList.Add(i.ToString());
            }

            // 构建动态筛选的数据流
            _dataSubscription = _filterTrigger
                .StartWith(string.Empty) // 初始显示全部数据
                .Select(filter => SourceList.Connect().Filter(item => item.Contains(filter)))
                .Switch() // 自动切换到最新的筛选流,取消旧订阅
                .Bind(BindableList)
                .Subscribe();

            LB.ItemsSource = BindableList;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            _filterTrigger.OnNext("1");
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            _filterTrigger.OnNext("2");
        }

        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            _filterTrigger.OnNext("3");
        }

        // 清理订阅,避免内存泄漏
        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);
            _dataSubscription?.Dispose();
            _filterTrigger?.Dispose();
        }
    }
}

核心改进点

  • _filterTrigger作为筛选条件的发布者,点击按钮时推送新的筛选字符
  • Switch()操作符确保始终只有最新的筛选数据流生效,解决多订阅冲突
  • 窗口关闭时手动释放资源,避免内存泄漏
  • 初始化时通过StartWith设置初始状态,显示所有数据

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 04:53:07