C# UI上的多线程WPF

C# UI上的多线程WPF,c#,wpf,multithreading,C#,Wpf,Multithreading,在我的C#WPF应用程序中,我有一个DataGrid,在它的正上方有一个TextBox,供用户在键入时搜索和过滤网格。但是,如果用户键入速度很快,则在键入后2秒钟内不会显示任何文本,因为UI线程正忙于更新网格 <TextBox Grid.Row="0" Text="{Binding SearchTerm, UpdateSourceTrigger=PropertyChanged}" /> <ListBox ItemsSource="{Binding ValuesView}"

在我的C#WPF应用程序中,我有一个
DataGrid
,在它的正上方有一个
TextBox
,供用户在键入时搜索和过滤网格。但是,如果用户键入速度很快,则在键入后2秒钟内不会显示任何文本,因为UI线程正忙于更新网格

<TextBox Grid.Row="0" Text="{Binding SearchTerm, UpdateSourceTrigger=PropertyChanged}" />

<ListBox ItemsSource="{Binding ValuesView}"
         Grid.Row="1" />
由于大部分延迟都发生在UI端(即过滤数据源几乎是即时的,但重新绑定和重新呈现网格的速度很慢),因此多线程并没有什么帮助。然后,我尝试在网格更新时将网格的调度程序设置为较低级别,但这也没有解决问题。这里有一些代码。。。对如何解决这类问题有什么建议吗

string strSearchQuery = txtFindCompany.Text.Trim();

this.dgCompanies.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(delegate
    {
        //filter data source, then
        dgCompanies.ItemsSource = oFilteredCompanies;
    }));
<TextBox Grid.Row="0" Text="{Binding SearchTerm, UpdateSourceTrigger=PropertyChanged}" />

<ListBox ItemsSource="{Binding ValuesView}"
         Grid.Row="1" />

如果您的目标是.net 4.5,一个选项是在
文本框
上设置
延迟
属性,这将阻止设置源值,直到满足某个时间阈值(直到用户停止键入)

<TextBox Grid.Row="0" Text="{Binding SearchTerm, UpdateSourceTrigger=PropertyChanged}" />

<ListBox ItemsSource="{Binding ValuesView}"
         Grid.Row="1" />

在没有用户输入以设置源值后,这将等待1秒

<TextBox Grid.Row="0" Text="{Binding SearchTerm, UpdateSourceTrigger=PropertyChanged}" />

<ListBox ItemsSource="{Binding ValuesView}"
         Grid.Row="1" />

另一种选择是让一个按钮触发筛选/搜索,而不是在文本框更改时触发。

使用ListCollectionView作为网格的项目源,更新筛选比重新分配项目源快得多

<TextBox Grid.Row="0" Text="{Binding SearchTerm, UpdateSourceTrigger=PropertyChanged}" />

<ListBox ItemsSource="{Binding ValuesView}"
         Grid.Row="1" />
下面的示例只需在setter中刷新搜索词text属性的视图,即可过滤100000行,没有明显的延迟

<TextBox Grid.Row="0" Text="{Binding SearchTerm, UpdateSourceTrigger=PropertyChanged}" />

<ListBox ItemsSource="{Binding ValuesView}"
         Grid.Row="1" />
视图模型

class ViewModel
    {
        private List<string> _collection = new List<string>(); 
        private string _searchTerm;

        public ListCollectionView ValuesView { get; set; }

        public string SearchTerm
        {
            get
            {
                return _searchTerm;
            }
            set
            {
                _searchTerm = value;
                ValuesView.Refresh();
            }
        }

        public ViewModel()
        {
            _collection.AddRange(Enumerable.Range(0, 100000).Select(p => Guid.NewGuid().ToString()));

            ValuesView = new ListCollectionView(_collection);
            ValuesView.Filter = o =>
                {
                    var listValue = (string)o;
                    return string.IsNullOrEmpty(_searchTerm) || listValue.Contains(_searchTerm);
                };
        }
    }
<TextBox Grid.Row="0" Text="{Binding SearchTerm, UpdateSourceTrigger=PropertyChanged}" />

<ListBox ItemsSource="{Binding ValuesView}"
         Grid.Row="1" />
类视图模型
{
私有列表_collection=新列表();
私有字符串_searchTerm;
public ListCollectionView值视图{get;set;}
公共字符串搜索项
{
得到
{
返回搜索条件;
}
设置
{
_搜索项=值;
ValuesView.Refresh();
}
}
公共视图模型()
{
_collection.AddRange(Enumerable.Range(0,100000).Select(p=>Guid.NewGuid().ToString());
ValuesView=新列表集合视图(\u集合);
ValuesView.Filter=o=>
{
var listValue=(字符串)o;
返回字符串.IsNullOrEmpty(_searchTerm)| | listValue.Contains(_searchTerm);
};
}
}
查看

<TextBox Grid.Row="0" Text="{Binding SearchTerm, UpdateSourceTrigger=PropertyChanged}" />

<ListBox ItemsSource="{Binding ValuesView}"
         Grid.Row="1" />

<TextBox Grid.Row="0" Text="{Binding SearchTerm, UpdateSourceTrigger=PropertyChanged}" />

<ListBox ItemsSource="{Binding ValuesView}"
         Grid.Row="1" />


发布您当前的XAML。很可能您正在破坏UI虚拟化,这就是UI“缓慢”的原因。你应该使用
CollectionView
来做这个。是的。例如:存在快速网格。UI是单线程的,但是2秒的时间太多了——这应该考虑一下。不要试图解决真正的问题,这是一个2秒的更新开始。这不是虚拟化。我知道,因为我可以关闭它,并将经历更长的加载时间。这需要1-2秒,因为如果用户快速键入单词“test”,网格会反弹4次,每个字母一次。谢谢!Shoe建议的延迟解决了问题,但我也会实施并测试您的建议,看看是否有更好的表现。再次感谢
<TextBox Grid.Row="0" Text="{Binding SearchTerm, UpdateSourceTrigger=PropertyChanged}" />

<ListBox ItemsSource="{Binding ValuesView}"
         Grid.Row="1" />