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
>
您似乎遇到的问题是,您正在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();
}
}
}