WPF基于ComboBox实现(花里胡哨)搜索功能与占位符提示

WPF基于ComboBox实现(花里胡哨)搜索功能与占位符提示

2023年7月19日发(作者:)

WPF基于ComboBox实现(花里胡哨)搜索功能与占位符提示

目标

首先,网上还有很多更高级的方式来实现题目中描述的功能,比如自定义样式,自定义控件(应该叫那个)。在这里,我只记录我的个人经历。毕竟花了很长时间才明白其中的一些原理。

一、实现搜索功能

ComboBox本身已经具备搜索功能,只需要将其IsEditable和IsTextSearchEnable开关打开就可以了。但是这个搜索功能是比较简单的,它能够帮你定位到第一个(如果有的话)匹配项。我想实现的是根据搜索文字更新列表内容,理由是这样更加酷炫。下面是实现方法(和一些坑)。

1. ComboBox定义

首先!我们需要关闭IsTextSearchEnable,理由是:它不仅帮我们定位匹配项,同时还会将SelectedItem也设置成这一项,这样会给我们的代码带来逻辑混乱。具体解释如下:

从属性角度来看,ComboBox的SelectedIndex,SelectedItem和Text的更新顺序是从前往后的,搜索逻辑本来应该是基于Text去更新源,但是更新源的操作会导致Selected的更新,进而再次引起Text更新,那么逻辑就会变得未知且不可控(甚至程序行为会出现有断点和没断点时两个样的情况)从事件的角度来说,我观察到很奇怪的一点,即控件内部由Selected引起的更新优先级是高于用户的输入行为的,假如说我输入“六”,代码自动选中“六六六”这一项并开始更新Text以及其他属性,等到这些更新都完成了,用户输入的“六”才会开始去更新Text(甚至会更新多次),最终导致界面显示的和代码选中的内容不一致,而且由于逻辑上的混乱,很难在这个情况下去解决不一致的问题。

我们所用到的ComboBox大概长这样:

Text="{Binding SearchText}"

IsEditable="True"

IsTextSearchEnable="False"/>

基于这个定义,我们将搜索逻辑放到searchText的set方法中实现。

2. .cs代码

在.cs文件中(Model或者ViewModel都可以,如果是要将这个ComboBox写成自定义控件的话,Model是更方便的选择,并且后面许多功能都没法使用Binding),我们定义上面绑定的属性如下:

privateList ItemsSource;publicList FilterItems

{get;set;}privatestring mSearchText;publicstring

SearchText

{get{return mSearchText;}set{

mSearchText=value;

FilterItems=(x=>ns(value)).ToList();}} 至此,我们已经实现了一个可以搜索的ComboBox,效果是:在ComboBox里面输入文字,点击展开列表可以看到匹配项,点击能够选择。这篇文章当然到这里还没结束,但是后面都是锦上添花的东西,感兴趣的话可以继续看。

二、实现符合习惯的弹出功能

ComboBox自带StaysOpenOnEdit选项,能够在用户输入时保持下拉框弹出,便于用户直观看到搜索结果。但是它有两个问题:

1.

它是Stays而不是Change,也就是说如果用户输入时下拉框是弹出的,那么输入行为不会导致下拉框收回;但是如果输入时下拉框还没有弹出,它并不会自动弹出。

2.

当我们选中其中一项,然后想要删除某些字来重新搜索时,它并不会响应,或者说选中后的删除并不被认为是一种Edit行为。如果想要自定义ComboBox的弹出行为,就需要进行一点小小的修改:

Text="{Binding SearchText}"

IsEditable="True"

IsTextSearchEnable="False"

x:Name ="CBName"

IsDropDownOpen="{Binding IsDrop}"

GotFocus="GotFocus"/>

首先,我们给ComboBox的IsDropDownOpen属性绑定一个bool变量,便于我们控制它自己展开;同时,当我们点击ComboBox使其获得焦点时(在这之前它的下拉框应当是收回的),执行GotFocus函数,使其自动展开,从而不需要我们输入前还得点一下下拉按钮让它展开。有了这两个就可以定义出符合使用习惯的弹出行为。先给出代码:

privateList ItemsSource;publicList FilterItems

{get;set;}privatestring mSearchText;publicstring

SearchText

{get{return mSearchText;}set{

mSearchText=value;

FilterItems=(x=>ns(value)).ToList();

IsDrop =true;}}publicbool IsDrop

{get;set}publicvoidGotFocus(object

sender,RoutedEventArgs e){

DownOpen =true;}

这样,在我们点击ComboBox准备搜索时,以及输入中、删除时,下拉框都会保持弹出。当然,在我们选中其中一项的时候下拉框会自动收回,此时如果我们继续输入或者删除,下拉框也会重新弹出。不过,此时代码会有一个小bug,后面再介绍。

三、为ComboBox添加占位符,实现提示功能

有了GotFocus,再加上LostFocus,我们就可以实现在输入框为空、失去焦点时添加占位符提示用户输入,获得焦点时清空占位符供用户输入。下面是代码:

Text="{Binding SearchText}"

IsEditable="True"

IsTextSearchEnable="False"

x:Name ="CBName"

IsDropDownOpen="{Binding IsDrop}"

GotFocus="GotFocus"

LostFocus="LostFocus"/>

publicvoidGotFocus(object sender,RoutedEventArgs e){

DownOpen

=true;if(("占位符"))

="";}publicvoidLostFocus(object

sender,RoutedEventArgs e){

DownOpen

=false;if(OrEmpty()) ="占位符";}

这样,当焦点离开ComboBox的时候,如果文本为空,则会出现占位符进行提示,再次点击时占位符就会被自动清空。不过需要注意的时,这两个事件在程序一开始并不会被触发,仅靠上面的代码,在程序刚开始运行时会发现ComboBox为空,而且没有占位符,所以需要给mSearchText(而不是SearchText,避免不正确的更新)一个初始值"占位符"即可。不过,我们可以看到,当失去焦点时,LostFocus会将下拉框合上,而对的赋值又会在SearchText里面将其(试图)展开,从结果而言(在我的电脑上,win10,.NET

Framework 4.6.2,Visual Studio 2017)实际上并没有展开。原因尚不清楚,大家可以自己验证看看。不过这一问题会带来一个小问题,即"占位符"的存在可能导致SearchText的更新不正确,需要我们修改一下它的更新逻辑:

publicstring SearchText

{get{return mSearchText;}set{

mSearchText=value;if(value=="占位符"){

FilterItems=();}else{

FilterItems=(x=>ns(value)).ToList();

IsDrop =true;}}}

欸!这时候问题也消失了,同时确保了FilterItems的内容是正确的(当然,如果大家的电脑在失去焦点时下拉框没有展开,问题实际上不算一个问题,可以不用进行上面的分类判断)。至此,占位符功能就实现了。

四、消除最后一个小bug

认真观看的同学知道我前面提到一个bug,如果你不记得了,罚你提肛10下。具体来说,就是当我们选中某一项以后(例如“

发布者:admin,转转请注明出处:http://www.yc00.com/xiaochengxu/1689720598a280891.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信