【问题标题】:WPF Combobox search typing speedWPF Combobox 搜索打字速度
【发布时间】:2020-03-31 15:59:22
【问题描述】:

我有一个 WPF 组合框

<ComboBox BorderThickness="0" Name="cmb_songs_head" HorizontalAlignment="Right" SelectedItem="{Binding Path=T.SelectedSong, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding Path=T.SelectedSet.Songs, UpdateSourceTrigger=PropertyChanged}" />

当组合框被选中并且我输入时,它会从下拉列表中选择——这就是我想要的。例如:

Hall
Hold
Hollow
Lead

所以当我输入H 时,第一项被选中,Ho 选择第二项,Holl 选择第三项。

但是,我的程序的用户抱怨他们经常打字太慢,所以他们最终输入Hol,选择Hold,然后输入l,选择Lead;而不是将其视为Hollow 的一个输入。

有没有办法延长单词之间的超时时间?

【问题讨论】:

    标签: wpf input combobox


    【解决方案1】:

    绑定ComboBox.SelectedItem时可以设置Binding.Delay

    以下示例将绑定的延迟设置为 1500 毫秒。在延迟过去之前发生的绑定目标或源的每次更改都会重置延迟计时器:

    <ComboBox Name="cmb_songs_head" 
              StaysOpenOnEdit="True"
              IsEditable="True"
              SelectedItem="{Binding T.SelectedSong, Delay=1500}"
              ItemsSource="{Binding T.SelectedSet.Songs}" />
    

    备注

    可以简化绑定以增强可读性:
    ComboBox.SelectedItem 默认绑定TwoWay
    UpdateSourceTrigger.PropertyChangedItemsControl 属性的默认触发器。


    更新

    这是默认的搜索行为。通过键入,搜索匹配项并实际选择匹配项。

    由于匹配立即分配给ComboBox.SelectedItem,因此选择不匹配的内容可能会产生不必要的副作用。 Especially when the selection triggers an operation.

    如果您想自动选择最接近的匹配项或提出建议,我建议您改用集合过滤。

    我会编写一个附加行为,它侦听ComboBox.PreviewTextInputTextBoxBase.PreviewKeyUp 事件来处理过滤。
    以下示例在代码隐藏中处理此事件,并假定 ComboBox 项目类型为 stringBinding.Delay 设置为 5s:

    查看

    <ComboBox ItemsSource="{Binding T.SelectedSet.Songs}" 
              SelectedItem="{Binding T.SelectedSong, Delay=5000}"
              StaysOpenOnEdit="True" 
              IsEditable="True" 
              TextBoxBase.PreviewKeyUp="EditTextBox_OnPreviewKeyUp"
              PreviewTextInput="ComboBox_OnPreviewTextInput" />
    

    代码隐藏

    private void EditTextBox _OnPreviewKeyUp(object sender, KeyEventArgs e)
    {
      var editTextBox = e.OriginalSource as TextBox;
      var comboBox = sender as ComboBox;
    
      switch (e.Key)
      {
        case Key.Back:
        {
          MainWindow.FilterComboBoxItemsSource(sender as ComboBox, editTextBox.Text, editTextBox);
          int selectionStart = comboBox.SelectedItem == null
            ? editTextBox.CaretIndex
            : Math.Max(0, editTextBox.SelectionStart - 1);
          int selectionLength = comboBox.SelectedItem == null 
            ? 0 
            : editTextBox.Text.Length - selectionStart;
          editTextBox.Select(selectionStart, selectionLength);
          break;
        }
        case Key.Space:
        {
          MainWindow.FilterComboBoxItemsSource(sender as ComboBox, editTextBox.Text, editTextBox);
          break;
        }
        case Key.Delete:
        {
          int currentCaretIndex = editTextBox.CaretIndex;
          MainWindow.FilterComboBoxItemsSource(sender as ComboBox, editTextBox.Text, editTextBox);
          editTextBox.CaretIndex = currentCaretIndex;
          break;
        }
      }
    }
    
    private void ComboBox_OnPreviewTextInput(object sender, TextCompositionEventArgs e)
    {
      e.Handled = true;
    
      var editTextBox = e.OriginalSource as TextBox;
      string oldText = editTextBox.Text.Substring(0, editTextBox.SelectionStart);
      string newText = oldText + e.Text;
    
      FilterComboBoxItemsSource(sender as ComboBox, newText, editTextBox);
    }
    
    private void FilterComboBoxItemsSource(ComboBox comboBox, string predicateText, TextBox editTextBox)
    {
      ICollectionView collectionView = CollectionViewSource.GetDefaultView(comboBox.ItemsSource);
      if (!string.IsNullOrWhiteSpace(predicateText) 
        && !collectionView.SourceCollection
          .Cast<string>()
          .Any(item => item.StartsWith(predicateText, StringComparison.OrdinalIgnoreCase)))
      {
        int oldCaretIndex = editTextBox.CaretIndex == editTextBox.Text.Length
          ? predicateText.Length
          : editTextBox.CaretIndex;
        editTextBox.Text = predicateText;
        editTextBox.CaretIndex = oldCaretIndex;
        return;
      }
    
      collectionView.Filter = item => (item as string).StartsWith(string.IsNullOrWhiteSpace(predicateText) 
        ? string.Empty 
        : predicateText, StringComparison.OrdinalIgnoreCase);
    
      collectionView.MoveCurrentToFirst();
      editTextBox.Text = collectionView.CurrentItem as string;
      editTextBox.Select(predicateText.Length, editTextBox.Text.Length - predicateText.Length);
    }
    

    【讨论】:

    • 感谢有关简化绑定的提示。延迟并没有达到我想要的效果 - 我尝试将其设置为 30000(这应该给我 30 秒的时间来输入单词中的下一个字母);但它并没有改变延迟
    • 这对我有用。将延迟设置为 30,000 可以让我在按键后有 30 秒的时间,直到实际提交当前项目。
    • 我明白了。您正在使用不同的配置。您应该将ComboBox.IsEditableComboBox.StaysOpenOnEdit 属性都设置为true。与Binding.Delay 一起,您将体验到预期的行为。我假设您已经设置了这些属性。每当我想输入ComboBox时,我自然会设置IsEditable,这就是我没有问你的原因。
    • 但我不希望它是可编辑的。这是用户从中选择的只读列表
    猜你喜欢
    • 2015-10-09
    • 1970-01-01
    • 2015-05-13
    • 2015-12-16
    • 2018-01-01
    • 1970-01-01
    • 2017-09-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多