【问题标题】:WPF combobox textsearch with contains带有包含的 WPF 组合框文本搜索
【发布时间】:2019-06-28 06:46:20
【问题描述】:

如何使用contains 而不是StartsWith 来实现我的组合框文本搜索

<rf:ComboBox Grid.Row="1"
                         Grid.Column="5"
                         Width="200"
                         ItemsSource="{Binding Source={StaticResource AccountProvider}}"
                         DisplayMemberPath="Description"
                         SelectedValuePath="IndRekId"
                         IsEmptyItemVisible="True"
                         SelectedValue="{Binding Id, UpdateSourceTrigger=PropertyChanged}"
                         IsTextSearchEnabled="True"
                         TextSearch.TextPath="Description"
                         IsEditable="True"/>

搜索功能有效,但我需要匹配子字符串

【问题讨论】:

  • 据我所知,实现这一点的唯一方法是创建一个扩展 ComboBox 的控件并添加您需要的功能。

标签: wpf search combobox


【解决方案1】:

这里我有一个 MVVM 框架的例子。

我的 xaml 文件:

<ComboBox Name="cmbContains" IsEditable="True" IsTextSearchEnabled="false" ItemsSource="{Binding pData}"  DisplayMemberPath="wTitle" Text="{Binding SearchText ,Mode=TwoWay}"  >
  <ComboBox.Triggers>
      <EventTrigger RoutedEvent="TextBoxBase.TextChanged">
          <BeginStoryboard>
              <Storyboard>
                  <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsDropDownOpen">
                      <DiscreteBooleanKeyFrame Value="True" KeyTime="0:0:0"/>
                  </BooleanAnimationUsingKeyFrames>
              </Storyboard>
          </BeginStoryboard>
      </EventTrigger>
  </ComboBox.Triggers>
</ComboBox>

我的cs文件:

//ItemsSource - pData
//There is a string attribute - wTitle included in the fooClass (DisplayMemberPath)
private ObservableCollection<fooClass> __pData;
public ObservableCollection<fooClass> pData {
    get { return __pData; }
    set { Set(() => pData, ref __pData, value);
        RaisePropertyChanged("pData");
    }
}

private string _SearchText;
public string SearchText {
    get { return this._SearchText; }
    set {
        this._SearchText = value;
        RaisePropertyChanged("SearchText");

        //Update your ItemsSource here with Linq
        pData = new ObservableCollection<fooClass>{pData.ToList().Where(.....)};
    }
}

您可以看到可编辑的组合框正在绑定到字符串(SearchText) 一旦出现 TextChanged 事件,就会显示下拉菜单,并且双向绑定会更新该值。 在进入 set{} 时,cs 文件中的 ItemsSource 发生了变化;语法。

https://gist.github.com/tonywump/82e66abaf71f715c4bd45a82fce14d80

【讨论】:

    【解决方案2】:

    这个示例看起来像“TextSearch”

    在 XAML 文件中,您应该只向组合框“TextContainSearch.Text”添加一个属性:

    <ComboBox ItemsSource="{Binding Model.formListIntDeviceNumbers}" SelectedItem="{Binding Path=Model.selectedDeviceNumber, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="DeviceNumber" IsEditable="True" c:TextContainSearch.Text="DeviceNumber">
    

    我们应该在 XAML 文件的头部添加 using:

    xmlns:c="clr-namespace:Adaptive.Controls.Extension"
    

    以及 *.cs 文件中的 C# 代码:

    using System;
    using System.Windows;
    using System.Windows.Controls;
    namespace Adaptive.Controls.Extension
    {
     public sealed class TextContainSearch : DependencyObject {
            public static void SetText(DependencyObject element, string text) {
                var controlSearch = element as Control;
                if (controlSearch != null)
                    controlSearch.KeyUp += (sender, e) =>
                    {
                        if (sender is ComboBox){
                            var control = sender as ComboBox;
                            control.IsDropDownOpen = true;
                            var oldText = control.Text;
                            foreach(var itemFromSource in control.ItemsSource){
                                if (itemFromSource != null)
                                {
                                    Object simpleType = itemFromSource.GetType().GetProperty(text).GetValue(itemFromSource, null);
                                    String propertOfList = simpleType as string;
                                    if (!string.IsNullOrEmpty(propertOfList) && propertOfList.Contains(control.Text))
                                    {
                                        control.SelectedItem = itemFromSource;
                                        control.Items.MoveCurrentTo(itemFromSource);
                                        break;
                                    }
                                }
                            }
                            control.Text = oldText;
                            TextBox txt = control.Template.FindName("PART_EditableTextBox", control) as TextBox;
                            if (txt != null)
                            {
                                txt.Select(txt.Text.Length, 0);
                            }
                        }
                    };
            }
        }
    }
    

    【讨论】:

    • 这个 sn-p 中的模式叫什么?我知道附加属性,并且大部分时间都将它们用于这个 sn-p 的作用 - 注册到控件的事件。尽管我从未见过这种情况,并且对您的方法的工作原理非常感兴趣。
    • 嗨@Evgenii,但是在SetText(DependencyObject element, string text) 中,“text”参数的值始终是“DeviceNumber”字符串。所以我输入的文本没有反映在那里。有什么原因吗?
    【解决方案3】:

    试试这个:

     <ComboBox Padding="3,5" MinWidth="150" SelectedItem="{Binding NewBoxRequest}"
     ItemsSource="{Binding Requests}" DisplayMemberPath="SN" IsEditable="True"
     StaysOpenOnEdit="True"
     Text="{Binding SnFilter,UpdateSourceTrigger=PropertyChanged}">
     </ComboBox>
    

    查看模型:

        private string snFilter;
    
        public string SnFilter
        {
            get { return snFilter; }
            set
            {
                snFilter = value;
                RaisePropertyChanged();
                RaisePropertyChanged(nameof(Requests));
            }
        }
        private List<Request> requests;
    
        public List<Request> Requests
        {
            get => string.IsNullOrEmpty(SnFilter) || requests.Any(r => r.SN == SnFilter)
                ? requests
                : requests.Where(r => r.SN.Contains(SnFilter)).ToList();
            set
            {
                requests = value;
                RaisePropertyChanged();
            }
        }
    

    【讨论】:

    • 这是最简单的 - 我不确定 requests.Any() 条件是什么,我没有包含它,也没有发现任何问题
    【解决方案4】:

    没有办法用 string.Contains() 替换 string.StartsWith()。您必须编写自定义 ComboBox。

    这篇文章可以帮助你: http://www.codeproject.com/Tips/631196/ComboBox-with-Suggest-Ability-based-on-Substring-S

    【讨论】:

      【解决方案5】:

      我无法让“Set”语法在我的 C# 系统中工作,所以这里是对 Wu 上述回答的一个小插曲(这是在自定义控件中):

       <ComboBox IsEditable="True" 
            IsTextSearchEnabled="false" 
            ItemsSource="{Binding pData, RelativeSource = {RelativeSource TemplatedParent}}"  
            DisplayMemberPath="description" 
            Text="{Binding SearchText , RelativeSource = {RelativeSource TemplatedParent}, Mode=TwoWay}"  >
           <ComboBox.Triggers>
                                          <EventTrigger RoutedEvent="TextBoxBase.TextChanged">
                                              <BeginStoryboard>
                                                  <Storyboard>
                                                      <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsDropDownOpen">
                                                          <DiscreteBooleanKeyFrame Value="True" KeyTime="0:0:0"/>
                                                      </BooleanAnimationUsingKeyFrames>
                                                  </Storyboard>
                                              </BeginStoryboard>
                                          </EventTrigger>
                                      </ComboBox.Triggers>
                                  </ComboBox>
      

      在自定义控件中:

      private async void _Loaded(object sender, RoutedEventArgs e)
              {
                  var n = await InitializeLabTests;
      
                  allTests = new ObservableCollection<CommonProcedure>(n);
                  pData = new ObservableCollection<CommonProcedure>(n);
              }
      
      //ItemsSource - pData
              //There is a string attribute - wTitle included in the fooClass (DisplayMemberPath)
              private ObservableCollection<CommonProcedure> __pData;
              public ObservableCollection<CommonProcedure> pData
              {
                  get { return __pData; }
                  set { __pData = value; RaisePropertyChanged(); }
              }
      
              private string _SearchText;
              public string SearchText
              {
                  get { return _SearchText; }
                  set
                  {
                      _SearchText = value; RaisePropertyChanged();
      
                      //Update your ItemsSource here with Linq
                      pData = new ObservableCollection<CommonProcedure>
                     (
                          allTests.Where(q => q.description.Contains(SearchText))
                     );
                  }
              }
      

      唯一显着的区别在于 SearchText 设置器。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-15
        • 2010-11-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-13
        相关资源
        最近更新 更多