c#wpf本地存储DataGrid集合,并使用Textbox进行过滤

本文关键字:Textbox 过滤 存储 DataGrid 集合 c#wpf | 更新日期: 2023-09-27 18:21:41

我创建了一个简单的wmi查询,然后创建了一种自定义集合。我添加了一个过滤器,它从文本更改事件的文本框中获取字符串。它按预期工作,但有一个主要缺点,每次尝试过滤时,它实际上都在进行整个查询。我希望它将集合存储在本地,并对本地var进行操作,而不是一遍又一遍地执行wmi查询。我尝试过多桩的方法,但到目前为止没有成功。任何帮助都将被通知!:)

以下是我尝试过的一种方式。。。

主cs:

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Data;
namespace myfilter
{
    public partial class FilteringSample : Window
    {
        public FilteringSample()
        {
            InitializeComponent();
            myProcesses items = new myProcesses();
            lvUsers.ItemsSource = items.GetProcesses;
            CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(lvUsers.ItemsSource);
            view.Filter = UserFilter;
        }
        private bool UserFilter(object item)
        {
            if (String.IsNullOrEmpty(txtFilter.Text))
                return true;
            else
                return ((item as myProcess).Name.IndexOf(txtFilter.Text, StringComparison.OrdinalIgnoreCase) >= 0);
        }
        private void txtFilter_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
        {
            CollectionViewSource.GetDefaultView(lvUsers.ItemsSource).Refresh();
        }
    }
}

cs类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Text;
using System.Threading.Tasks;
namespace myfilter
{
    class myProcesses
    {
        public IEnumerable<myProcess> GetProcesses
        {
            get
            {
                ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select * From Win32_Process");
                ManagementObjectCollection processList = searcher.Get();
                myProcess myproc;
                foreach (ManagementObject obj in processList)
                {
                    if (obj != null)
                    {
                        myproc = new myProcess();
                        try
                        {
                            myproc.Name = obj["Name"].ToString();
                        }
                        catch { }
                        try
                        {
                            myproc.ID = obj["ProcessId"].ToString();
                        }
                        catch { }
                        yield return myproc;
                    }
                }
            }
        }
    }
    class myProcess
    {
        public string Name { get; set; }
        public string ID { get; set; }
    }
}

XAML:

<Window x:Class="myfilter.FilteringSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="FilteringSample" Height="200" Width="300">
    <DockPanel Margin="10">
        <TextBox DockPanel.Dock="Top" Margin="0,0,0,10" Name="txtFilter" TextChanged="txtFilter_TextChanged" />
        <DataGrid Name="lvUsers">
        </DataGrid>
    </DockPanel>
</Window

>

c#wpf本地存储DataGrid集合,并使用Textbox进行过滤

您似乎遇到的问题是,您正在UI(调度器)线程上执行所有工作(查询WMI)。如果你想让用户界面在用户使用应用程序时保持响应,而不是"白屏"或冻结,你就必须使用异步方法来查询数据。

.Net框架有几个部分可以帮助您做到这一点:

  • TPL(任务<T>)
  • 背景工人班
  • 线程类

举几个例子,另外还有Rx(Reactive Extensions for.Net)等技术,它们封装并提供了一个定义良好的API来处理异步问题。

无论你选择哪种解决方案,你都必须处理从后台线程更新UI的问题,有很多关于如何在SO上做到这一点的例子。

当然,在程序中引入异步执行通常会增加任何代码库的复杂性,尤其是UI代码,但如果您希望应用程序从用户的角度保持性能,这就是成本。

毕竟,如果你不想使用异步方法,你可以将WMI查询的结果缓存在myProcesses类中一段特定的时间,比如说1分钟,因此,任何未来的请求都将返回这些结果,而不是执行另一个查询,并且一旦1分钟到期,您将清除缓存的结果,并且未来的查询将再次针对WMI执行,再次重复该过程。

我想我是自己想出来的。我把数据存储在中

ObservableCollection<>

这让我可以在本地检查过滤结果,而不会再次重新启动查询。如果有人感兴趣,这里是修改后的代码(更改仅在主cs中进行):

namespace filter
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        ObservableCollection<myProcess> myCollection;
        public MainWindow()
        {
            InitializeComponent();
            myProcesses items = new myProcesses();
            myCollection = new ObservableCollection<myProcess>();
            foreach (myProcess localproc in items.GetProcesses)
            {
                myCollection.Add(localproc);
            }
            lvUsers.ItemsSource = myCollection;
            CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(myCollection);
            view.Filter = UserFilter;
        }
        private bool UserFilter(object item)
        {
            if (String.IsNullOrEmpty(txtFilter.Text))
                return true;
            else
                return ((item as myProcess).Name.IndexOf(txtFilter.Text, StringComparison.OrdinalIgnoreCase) >= 0);
        }
        private void txtFilter_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
        {
            CollectionViewSource.GetDefaultView(myCollection).Refresh();
        }
    }
}