最近在项目中碰到一个需求,需要在ComboBox中提供一个树形菜单以方便体现其中的层次关系,比较典型的一个应用就是在权限管理中,给用户赋予一个有继承关系的角色,那么这个角色的显示,用带有树形显示的下拉框就非常的方便,不用搞什么级联下拉。但是愿望是好的,现实却是残酷的,这个看似简单的需求,我找遍了百度与google,只找到非常有限的几篇文章,虽然实现的很不错,但是奈何我水平有限看不懂啊…… 大神们都是继承并重写一个ComboBox控件,将一个TreeView控件作为其一个属性,但是其中涉及到的控制代码我看不懂,感兴趣的可以通过【这里】看看他们的文章,还有【这篇】是国外大神Bradley Smith的文章,他着重分析了ComboBox控件的一些呈现特征以及WinForm时代大家通过Form来模拟带TreeView下拉框的方法的弊端,然后提出了他的解决方案,当然也是重写控件喽,而且他不仅授人以渔,同时还授人以鱼,文末有源代码下载哦~ E文不好的同学还可以看博客园论坛里的【这篇】翻译。
好了,废话说完了(额…… 其实大神们的才是精华,我的才是废话……)。总之我们进入正题:带有TreeView控件的ComboBox 之 菜鸟的实现方法
要实现带有TreeView控件的ComboBox,最容易想到的方法当然是直接在ComboBox的ComboBoxItem中嵌套一个TreeView控件,代码如下图:
效果是像模像样的出来了,但是这样写的话会有一个问题,大家看下图就知道:
没错,整个TreeView控件都被作为ComboBox的一个选择结果呈现在ComboBox中,真是要多难看有多难看…… 那么为什么会这样呢?我们知道,ComboBox可以绑定复杂的一个结构,通常是我们自定义的一个对象模型,我们在ComboBox中呈现的只是这个对象中的某个字段,我们可以通过ComboBox的DisplayMemberPath属性和SelectedValuePath属性设置显示的是哪个字段的值而选中的结果是哪个字段的值。而现在我们在ComboBoxItem中放了一个TreeView控件,相当于我们的内容就是一个TreeView,因此选中后自然将整个TreeView作为选中的结果给显示在ComboBox当中。那可不可以通过ComboBox中的DisplayMemberPath属性来设置其选中后显示我们在TreeView中选中的值呢?非常不幸,不可以!原因是我们的TreeView控件是个复杂的控件,其TreeViewItem同样可以绑定一个复杂的对象,当我们选中一个节点后,绑定在这个节点上的数据被赋值到TreeView的SelectedItem属性当中,所以即使我们给ComboBox的DisplayMemberPath属性赋上SelectedItem让它呈现TreeView选中的内容,那么得到的也是绑定在TreeViewItem上的某个对象,而我们真正想要得到的却是这个对象中的某个字段。相当于我们的呈现值跟目标对象隔了两层封装,而设置DisplayMemberPath属性只能解开一层。所以这个方案行不通。
既然强攻的不行,那我们只好巧取了!
既然DisplayMemberPath只能解开一层封装,那我们就直接将我们的目标对象绑定在ComboBoxItem当中,然后用DisplayMemberPath指定需要显示的属性。但是,这个绑定了目标对象的ComboBoxItem只是一个中转,帮助我们呈现结果用的,而实现树形列表的仍旧交给TreeView控件,我们的思路是这样的,当我们点击TreeView控件的某个节点时,我们得到绑定在该节点上的目标对象,然后我们将该对象赋值给中转用的ComboBoxItem,然后让ComboBox显示这个中转用的ComboBoxItem,这样就解决了我们的问题。
其中第一个ComboBoxItem中绑定的就是我们的目标对象,那这个ComboBoxItem就是用于中转并呈现的项,至于把它高度设置成0是为了在我们点开下拉框的时候不要在TreeView上面还冒出一行选项来。而上面的代码中还涉及到的两个事件:ComboBox的SelectionChanged事件和TreeView的SelectedItemChanged事件,则分别用来实现让ComboBox选项改变时总是呈现第一个ComboBoxItem,和当TreeView选项改变时将选中的值赋给第一个ComboBoxItem所绑定的那个对象。 下拉与选中后的效果如下
还挺逼真的有木有~~ 跟大神们用继承做出来的效果一样,小小傲娇一把~ 用这个方法来做完全是我们对已有基础的灵活运用,不需要掌握什么更高深的原理,简单易懂。但是话又说回来,如果大家都只关注实现而不去深入研究,那自己的技术也永远也无法提高了。
好了,文章至此,希望能对大家有所帮助,如有转载,请尊重原创,注明出处!
以上。
原文地址:http://www.freebluer.net/wpf-combobox-with-treeview.html