为什么搜索框自动建议显示缓慢

时间:2020-10-21 02:31:32

标签: c# wpf autosuggest search-suggestion search-box

我实现了SearchTextBox,它终于可以工作了,但是速度却很慢(5到7秒钟后就会显示自动提示)。我从CSV文件中读取内容,并创建了一个对象类型“可观察的集合”,然后将其转储到RecommendationionSource中,然后在搜索框文本更改时过滤结果。总共大约有700条建议,每个建议有50-100个字符。在这种情况下变慢还是我做错了是正常的吗?

XAML:

<controls:SearchTextBox x:Name="SearchLayersBox" Height="23" Margin="5,5,10,10" VerticalAlignment="Top" InfoText="Search" SearchMode="Auto" ShowHistory="True" Search="SearchTextBox_Search" Initialized="SearchLayersBox_Initialized" TextChanged="SearchLayersBox_TextChanged" SuggestionListMax="15" />

C#

public void LayersListSearchBox()
{
    LayerDict.Clear();
    DataListBoxSource.Clear();
    var path = @"\\nrdsmnt6\mine maps\DMP_Database\Layer_Properties_spc_CSV.csv";

    using (TextFieldParser csvParser = new TextFieldParser(path))
    {
       csvParser.SetDelimiters(new string[] { "*%&" });
       csvParser.HasFieldsEnclosedInQuotes = false;
       //Skip the row with the column names
       csvParser.ReadLine();

       while (!csvParser.EndOfData)
          {
             string[] fields = csvParser.ReadFields();
 
             string LayerDisplayName = fields[3].Substring(1);

             SearchSuggestCollection.Add(LayerDisplayName);
          }
    }
 
    SearchLayersBox.SuggestionSource = SearchSuggestCollection;
 }

 

private void SearchLayersBox_TextChanged(object sender, TextChangedEventArgs e)
{
    string searchString = SearchLayersBox.Text;

    ObservableCollection<object> filteredCollection = new ObservableCollection<object>(from objectL in SearchSuggestCollection where objectL.ToString().Contains(searchString) select objectL);

    SearchLayersBox.SuggestionSource = filteredCollection;

}

 

private void SearchLayersBox_Initialized(object sender, EventArgs e)
{
   LayersListSearchBox();
}

更新1

阅读评论后,我切换到ICollectionView来过滤 ObservableCollection

public ICollectionView SearchView
        {
            get { return CollectionViewSource.GetDefaultView(SearchSuggestCollection); }
        }

,并按照ASh的answer

的建议,通过@Bandook和@ASh建议插入到SearchView的绑定。
<controls:SearchTextBox x:Name="SearchLayersBox" SuggestionSource="{Binding SearchView, UpdateSourceTrigger=PropertyChanged}" Height="23" Margin="5,5,10,10" VerticalAlignment="Top" InfoText="Search" SearchMode="Auto" ShowHistory="True" Search="SearchTextBox_Search" Initialized="SearchLayersBox_Initialized" TextChanged="SearchLayersBox_TextChanged" SuggestionListMax="15" />

此外,在自动提示显示之前,我至少需要输入三个字母。

private void SearchLayersBox_TextChanged(object sender, TextChangedEventArgs e)
        {
 
            string searchString = SearchLayersBox.Text;

            if (searchString.Length >= 3)
            {
                SearchView.Filter = item =>
                {
                    return item.ToString().Contains(searchString);
                };
            }

           
        }

我认为与SearchView的绑定不起作用。这是创建绑定的不正确方法吗?

SuggestionSource="{Binding SearchView, UpdateSourceTrigger=PropertyChanged}"

更新2

尝试了太多失败之后,我找不到合适的解决方案,但是在删除了最初的AskedSource分配并且在发出建议之前至少需要3个字母之后,我才使解决方案变得非常快

XAML:

<controls:SearchTextBox x:Name="SearchLayersBox" Height="23" 
Margin="5,5,10,10" VerticalAlignment="Top" InfoText="Search here" 
SearchMode="Auto" ShowHistory="True" Search="SearchTextBox_Search" 
Initialized="SearchLayersBox_Initialized" 
TextChanged="SearchLayersBox_TextChanged" SuggestionListMax="15" />

C#

   private ObservableCollection<object> _searchSuggestionCollection;
        public ObservableCollection<object> SearchSuggestCollection
        {
            get { return _searchSuggestionCollection; }
            set
            {
                if (_searchSuggestionCollection != value)
                {
                    _searchSuggestionCollection = value;
                    OnPropertyChanged();
                }
            }
        }

void LayersListSearchBox()
        {
            LayerDict.Clear();
            DataListBoxSource.Clear();
            var path = @"\\nrdsmnt6\mine maps\DMP_Database\Layer_Properties_spc_CSV.csv";
            SearchSuggestCollection = new ObservableCollection<object>();

            using (TextFieldParser csvParser = new TextFieldParser(path))
            {
                csvParser.SetDelimiters(new string[] { "*%&" });
                csvParser.HasFieldsEnclosedInQuotes = false;
                //Skip the row with the column names
                csvParser.ReadLine();

                while (!csvParser.EndOfData)
                {
                    string[] fields = csvParser.ReadFields();
     
                    string LayerDisplayName = fields[3].Substring(1);

                    SearchSuggestCollection.Add(LayerDisplayName);
                }
            }
        }

private void SearchLayersBox_Initialized(object sender, EventArgs e)
        {
            LayersListSearchBox();
        }

private void SearchLayersBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            string searchString = SearchLayersBox.Text;
            SearchLayersBox.SuggestionSource = null;

            if (searchString.Length >= 3)
            {
                ObservableCollection<object> filteredCollection = new ObservableCollection<object>(from objectL in SearchSuggestCollection where objectL.ToString().Contains(searchString) select objectL);

                SearchLayersBox.SuggestionSource = filteredCollection;
            }
    }

1 个答案:

答案 0 :(得分:1)

您可以通过将string.Contains替换为string.StartsWith来缩短查找时间。这将大大改善字符串解析,因为Contains会触摸每个条目。
如果要允许使用不同的搜索模式(例如开头,结尾或包含),则应将搜索配置为可配置的,以限制所需的行为,以将对性能的影响降到最低。

搜索也应在自定义SearchTextBox控件内实现。为此,您应该覆盖TextBoxBase.OnTextChanged

class SearchTextBox : TextBox
{
  // This MUST be a DependencyProperty to allow being set via data binding
  public IEnumerable SuggestionSource { get; set; }

  protected override void OnTextChanged(TextChangedEventArgs e)
  {
    string searchString = this.Text;
    if (this.SuggestionSource == null || searchString.Length < 3)
    {
      return;
    }

    ICollectionView suggestionsView = CollectionViewSource.GetDefaultView(this.SuggestionSource);
    suggestionsView.Filter = item => (item as string).StartsWith(searchString);           
  }
}

您甚至可以通过实现动态创建的查找树,通过将每个搜索关键字及其相关结果存储在字典或哈希表中来进一步提高查找速度。

您可以在后台线程中或在应用程序启动期间(显示初始屏幕时)准备查找字典,并将其存储在文件数据库中,以备下次应用程序启动时使用。
我建议准备所有三个字母,例如创建建议源集合时,通过遍历文件输入来确定五个字母组合。然后在后台完成查找字典,直到它包含与结果完全匹配的键,即对完整的输入源进行了索引。
这种查询字典消除了重复和昂贵的字符串比较。

示例:

输入:“宝藏”,“司库”。
索引:
条目1:“ Tre”:“ Treasure”,“ Treasurer”
条目2:“宝藏”:“宝藏”,“宝藏”
条目3:“宝藏”:“宝藏”,“司库”
...
条目6:“宝藏”:“宝藏”,“司库”
Entry7:“财务主管”:“财务主管”

如ASh所建议,您应该考虑实施延迟,例如在执行过滤器之前500ms,以避免在每次击键时进行过滤。您可以将此延迟设为可选,并在性能降低太多的情况下启用它。

相关问题