1

我刚开始使用 Redis,我正在将它用于我的个人项目之一。Redis DB 包含大约 10k 个对象

public Class FileList
{
    public string FileName { get; set;} 
    public string FolderName { get; set;}
}

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

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

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

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

是我将它添加ItemsListBox一个forach花费了这么多时间的中还是有什么可以做的来加速它,就像ItemSource我尝试过的那样但给了我错误ItemList should be empty before binding

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

代码

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>

更新 1:

添加了 ViewCollectionSource 如下

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

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

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更新需要 2 秒,第二个字符需要 1 秒。在此之后,几乎是瞬间。主列表中大约有 5000 项_fileList

有什么方法可以提高前 2 个字符搜索的速度?

4

3 回答 3

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

于 2013-10-27T09:27:50.520 回答
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 之后(排除这是您的 DB 错误)、然后在排序之前/之后打印到控制台,依此类推。这样,您可以看到最慢的因素是什么。

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

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

编辑:
您总是可以在用户输入 3 个字符后运行搜索,从而解决问题(假设有 10K 个项目,一个字母无论如何都无关紧要,他会继续搜索)。

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

最后但并非最不重要的一点是,这里有一个链接也可能有所帮助(解决您将项目添加到列表的第一个循环):为什么 AddRange 比使用 foreach 循环更快?

于 2013-10-27T11:13:32.960 回答
0

这些问题在我发现的 ListBox 中很常见,您是否检查过以确保数据虚拟化没有被禁用并且 VirtualizationMode 设置为“Recycling”?

我发现有帮助的另一件事是在输入最后一个字符后几秒钟使用 DispatchTimer 触发搜索。大多数用户不介意最后稍等片刻,但他们不希望 GUI 在打字时感觉迟钝。

于 2013-12-15T21:26:48.000 回答