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

时间:2014-09-11 12:43:52

标签: c# wpf datagrid filter collectionview

我创建了一个简单的wmi查询,然后创建了一个自定义集合。 我添加了一个过滤器,它从文本更改事件的文本框中获取字符串。 它按预期工作但有一个主要缺点,每次你尝试过滤它实际上都在进行查询。我想要它做的是存储集合localy并在该局部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();
        }
    }
}

class 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

&GT;

2 个答案:

答案 0 :(得分:0)

您似乎遇到的问题是您正在UI(调度程序)线程上执行所有工作(查询WMI)。如果您希望用户界面保持响应状态而不是白屏&#39;或者在用户使用您将要使用异步方法查询数据的应用程序时冻结。

.Net框架的几个部分可以帮助您:

  • TPL(任务&lt; T&gt;)
  • BackgroundWorker类,
  • 线程类,

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

您选择哪种解决方案,您将不得不处理从后台线程更新UI的问题,有很多关于如何在SO上执行此操作的示例。

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

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

答案 1 :(得分:0)

好吧我想我自己弄明白了。 我将数据存储在

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();
        }
    }

}