WPF C#4.5 ListBox更新非常慢

时间:2013-10-27 07:50:25

标签: c# wpf listbox redis .net-4.5

我刚开始使用Redis,我正在将它用于我的一个个人项目。

包含大约10k个对象
public Class FileList
{
    public string FileName { get; set;} 
    public string FolderName { get; set;}
}

我最初在加载时在ListBox ResultsView中显示此列表。我有TextBox我可以在其中输入字符,在TextBoxChanged_Event我正在调用一个函数,该函数将向RedisDB查询包含我在{中输入的字符的所有FileList个对象{1}}并将其存储在TextBox中,该ResultsList<FileList>将在foreach中循环播放,然后添加到ListBox

开始显示结果至少需要一秒钟,而且速度不是很快。

现在,如果我对MasterList<FileList>执行相同的查询,那么它会更快但仍然不够快。

昨天,我尝试使用RavenDb,这需要花费很长时间才能完成相同的任务。

我是否正在ItemsListBox添加到forach ItemSource这需要花费很多时间,或者是否有任何可以加快速度的ItemList should be empty before binding { {1}}我试过但却给了我ResultsView.Items.Clear(); var redisClient = new RedisClient("localhost"); using (var client = redisClient.As<FileList>()) { var foldersFromRedis = client.GetAll().Where(fileList => fileList.FileName.Contains(this.Search.Text.ToLower())); foreach (FileList fileList in foldersFromRedis) { var listViewItem = new ListViewItem { Content = fileList.FileName , Tag = fileList.FolderName }; this.ResultsView.Items.Add(listViewItem); } } //this.ResultsView.ItemsSource = ResultsFileList;

的错误

我确实尝试过几乎类似问题的大多数答案,但没有人帮助过我。

代码

<ListBox Height="374" ScrollViewer.VerticalScrollBarVisibility="Disabled" HorizontalAlignment="Left" Margin="10,0,0,0" Name="ResultsView" VerticalAlignment="Bottom" Width="405" BorderThickness="0" SelectionChanged="MovieNameSelectionChanged" FontFamily="Nobile" FontSize="13" Background="#A6FCFCFC" Foreground="Black" FontStretch="Normal">
  <GridView>
        <GridViewColumn Header="FileName" DisplayMemberBinding="{Binding FileName}"/>
        </GridView>
</ListBox>
 private void ApplyViewCollectionSource()
    {
        _viewSource.Filter += ViewSourceFilter;
        _viewSource.Source = _fileList = (List<FileList>)PopulateFileListEnglishWithReturn();
        ResultsView.ItemsSource = _viewSource.View;
        _timer.Interval = new TimeSpan(0, 0, 0, 0, 200);
        _timer.Tick += (o, e) =>
        {
            _timer.Stop();
            _viewSource.View.Refresh();
        };
        Search.TextChanged += (o, e) => _timer.Start();
    }

更新1:

添加了ViewCollectionSource,如下所示

private void ViewSourceFilter(object sender, FilterEventArgs e)
{

    var src = e.Item as FileList;
    e.Accepted = src != null;
    if (string.IsNullOrEmpty(Search.Text)) return;
    var regex = new Regex(Search.Text, RegexOptions.IgnoreCase);
    e.Accepted = regex.IsMatch(src.FileName);
}

在构造函数中调用。过滤器如下:

ListBox

这适用于我的要求,但仅限于TextBox中的第3个字符。键入第一个字符后,_fileList需要2秒才能更新,第二个字符需要1秒。在此之后,它几乎是瞬间。主列表{{1}}中有大约5000个项目。

在前2个字符搜索过程中提高速度的方法有哪些?

3 个答案:

答案 0 :(得分:0)

每次要过滤时都不要重新加载数据。 WPF具有过滤现有数据的机制,而无需往返服务器。考虑使用CollectionView为您进行过滤。集合视图允许您更改呈现给用户的内容,而无需触及数据本身。

您可以在此处找到一个有效的示例:http://social.msdn.microsoft.com/Forums/vstudio/en-US/0d2b882d-cf56-4385-9b76-dd280c4c35b1/filter-a-readonlycollection-for-binding-a-listview?forum=wpf#213dda80-5d29-47fa-b832-ea7e098590d7

答案 1 :(得分:0)

首先,我个人不喜欢空绑定...我给Window / UserControl一个名字

<Window ...
    Name="your_name_here">

然后在绑定中,绑定到后面的代码上的属性(假设它被称为property_for_binding),你将它绑定它:

<Listbox ...
   ItemSource={Binding ElementName=your_name_here , Path=property_for_binding} />

话虽如此,我确实更喜欢MVVM方法,但没关系,重新开始工作...... 您是否尝试在功能上添加一些秒表?您可以在调用DB之前打印到控制台,在调用DB(排除它是您的数据库错误)之后,然后在排序之前/之后打印,依此类推。通过这种方式,您可以看到最慢的因素。

正如评论所说,你可能不应该在数据库中查询文本框中的每个更改(假设您在文本更改时执行此操作,而不是在完成输入后通过按钮),因为通常您的数据库将给出相同的结果页面内的所有搜索(除非它从其他地方进行了大量修改,在这种情况下,我猜你没有其他选择)。

因此,缓存结果一次,搜索该变量,并用结果填充您要绑定的属性。

修改
你总是可以在用户输入3个字符之后运行搜索,解决问题(假设有10K项,一个字母无关紧要,他会继续搜索)。

其他选项是仅在上次击键后经过一段时间后才进行搜索。

最后但并非最不重要的是,这里有一个可能有用的链接(解决你在列表中添加项目的第一个循环):Why is AddRange faster than using a foreach loop?

答案 2 :(得分:0)

我发现ListBox这类问题很常见,您是否检查过以确保数据虚拟化未被禁用且VirtualizationMode设置为“回收”?

我发现另一件有用的事情是使用DispatchTimer在输入最后一个字符后的几秒钟内触发搜索。大多数用户不介意在结束时进行短暂的等待,但他们不希望GUI在打字时感到迟钝。