Seaching TreeVIew WPF
程序员文章站
2022-03-29 10:26:01
项目中有一个树形结构的资源,需要支持搜索功能,搜索出来的结果还是需要按照树形结构展示,下面是简单实现的demo。 1.首先创建TreeViewItem的ViewModel,一般情况下,树形结构都包含DisplayName,Deepth,Parent,Children,Id, IndexCode,Vi ......
项目中有一个树形结构的资源,需要支持搜索功能,搜索出来的结果还是需要按照树形结构展示,下面是简单实现的demo。
1.首先创建treeviewitem的viewmodel,一般情况下,树形结构都包含displayname,deepth,parent,children,id, indexcode,visibility等属性,具体代码如下所示:
1 using system; 2 using system.collections.generic; 3 using system.collections.objectmodel; 4 using system.linq; 5 using system.text; 6 using system.threading.tasks; 7 using system.windows; 8 9 namespace treeviewdemo 10 { 11 public class treeviewitemvm : notifypropertychangedbase 12 { 13 public treeviewitemvm () 14 { 15 visible = visibility.visible; 16 } 17 18 private treeviewitemvm parent; 19 public treeviewitemvm parent 20 { 21 get 22 { 23 return this.parent; 24 } 25 set 26 { 27 if (this.parent != value) 28 { 29 this.parent = value; 30 this.onpropertychanged(() => this.parent); 31 } 32 } 33 } 34 35 private observablecollection<treeviewitemvm> children; 36 public observablecollection<treeviewitemvm> children 37 { 38 get 39 { 40 return this.children; 41 } 42 set 43 { 44 if (this.children != value) 45 { 46 this.children = value; 47 this.onpropertychanged(() => this.children); 48 } 49 } 50 } 51 52 private string id; 53 public string id 54 { 55 get 56 { 57 return this.id; 58 } 59 set 60 { 61 if (this.id != value) 62 { 63 this.id = value; 64 this.onpropertychanged(() => this.id); 65 } 66 } 67 } 68 69 private string indexcode; 70 public string indexcode 71 { 72 get { return indexcode; } 73 set 74 { 75 if (indexcode != value) 76 { 77 indexcode = value; 78 this.onpropertychanged(() => indexcode); 79 } 80 } 81 } 82 83 private string displayname; 84 public string displayname 85 { 86 get 87 { 88 return this.displayname; 89 } 90 set 91 { 92 if (this.displayname != value) 93 { 94 this.displayname = value; 95 this.onpropertychanged(() => this.displayname); 96 } 97 } 98 } 99 100 private int deepth; 101 public int deepth 102 { 103 get 104 { 105 return this.deepth; 106 } 107 set 108 { 109 if (this.deepth != value) 110 { 111 this.deepth = value; 112 this.onpropertychanged(() => this.deepth); 113 } 114 } 115 } 116 117 private bool haschildren; 118 public bool haschildren 119 { 120 get 121 { 122 return this.haschildren; 123 } 124 set 125 { 126 if (this.haschildren != value) 127 { 128 this.haschildren = value; 129 this.onpropertychanged(() => this.haschildren); 130 } 131 } 132 } 133 134 private nodetype type; 135 public nodetype type 136 { 137 get { return type; } 138 set 139 { 140 if (type != value) 141 { 142 type = value; 143 onpropertychanged(() => this.type); 144 } 145 } 146 } 147 148 private visibility visible; 149 public visibility visible 150 { 151 get { return visible; } 152 set 153 { 154 if (visible != value) 155 { 156 visible = value; 157 onpropertychanged(() => this.visible); 158 } 159 } 160 } 161 162 public bool namecontains(string filter) 163 { 164 if (string.isnullorwhitespace(filter)) 165 { 166 return true; 167 } 168 169 return displayname.tolowerinvariant().contains(filter.tolowerinvariant()); 170 } 171 } 172 }
2.创建treeviewviewmodel,其中定义了用于过滤的属性filter,以及过滤函数,并在构造函数中初始化一些测试数据,具体代码如下:
1 using system; 2 using system.collections.generic; 3 using system.collections.objectmodel; 4 using system.componentmodel; 5 using system.linq; 6 using system.text; 7 using system.threading.tasks; 8 using system.windows.data; 9 10 namespace treeviewdemo 11 { 12 public class treeviewviewmodel : notifypropertychangedbase 13 { 14 public static treeviewviewmodel instance = new treeviewviewmodel(); 15 16 private treeviewviewmodel() 17 { 18 filter = string.empty; 19 20 root = new treeviewitemvm() 21 { 22 deepth = 0, 23 displayname = "五号线", 24 haschildren = true, 25 type = nodetype.unit, 26 id = "0", 27 children = new observablecollection<treeviewitemvm>() { 28 new treeviewitemvm() { displayname = "站台", deepth = 1, haschildren = true, id = "1", type = nodetype.region, 29 children = new observablecollection<treeviewitemvm>(){ 30 new treeviewitemvm() { displayname = "camera 01", deepth = 2, haschildren = false, id = "3",type = nodetype.camera }, 31 new treeviewitemvm() { displayname = "camera 02", deepth = 2, haschildren = false, id = "4",type = nodetype.camera }, 32 new treeviewitemvm() { displayname = "camera 03", deepth = 2, haschildren = false, id = "5",type = nodetype.camera }, 33 new treeviewitemvm() { displayname = "camera 04", deepth = 2, haschildren = false, id = "6",type = nodetype.camera }, 34 new treeviewitemvm() { displayname = "camera 05", deepth = 2, haschildren = false, id = "7", type = nodetype.camera}, 35 }}, 36 new treeviewitemvm() { displayname = "进出口", deepth = 1, haschildren = true, id = "10", type = nodetype.region, 37 children = new observablecollection<treeviewitemvm>(){ 38 new treeviewitemvm() { displayname = "camera 11", deepth = 2, haschildren = false, id = "13",type = nodetype.camera }, 39 new treeviewitemvm() { displayname = "camera 12", deepth = 2, haschildren = false, id = "14",type = nodetype.camera }, 40 new treeviewitemvm() { displayname = "camera 13", deepth = 2, haschildren = false, id = "15",type = nodetype.camera }, 41 new treeviewitemvm() { displayname = "camera 14", deepth = 2, haschildren = false, id = "16", type = nodetype.camera}, 42 new treeviewitemvm() { displayname = "camera 15", deepth = 2, haschildren = false, id = "17", type = nodetype.camera}, 43 }}, 44 } 45 }; 46 47 inittreeview(); 48 } 49 50 private observablecollection<treeviewitemvm> selectedcameras = new observablecollection<treeviewitemvm>(); 51 52 private treeviewitemvm root; 53 public treeviewitemvm root 54 { 55 get 56 { 57 return this.root; 58 } 59 set 60 { 61 if (this.root != value) 62 { 63 this.root = value; 64 this.onpropertychanged(() => this.root); 65 } 66 } 67 } 68 69 /// <summary> 70 /// 过滤字段 71 /// </summary> 72 private string filter; 73 public string filter 74 { 75 get 76 { 77 return this.filter; 78 } 79 set 80 { 81 if (this.filter != value) 82 { 83 84 this.filter = value; 85 this.onpropertychanged(() => this.filter); 86 87 this.refresh(); 88 } 89 } 90 } 91 92 /// <summary> 93 /// view 94 /// </summary> 95 protected icollectionview view; 96 public icollectionview view 97 { 98 get 99 { 100 return this.view; 101 } 102 set 103 { 104 if (this.view != value) 105 { 106 this.view = value; 107 this.onpropertychanged(() => this.view); 108 } 109 } 110 } 111 112 /// <summary> 113 /// 刷新view 114 /// </summary> 115 public void refresh() 116 { 117 if (this.view != null) 118 { 119 this.view.refresh(); 120 } 121 } 122 123 private bool dofilter(object obj) 124 { 125 treeviewitemvm item = obj as treeviewitemvm; 126 if (item == null) 127 { 128 return true; 129 } 130 131 bool result = false; 132 foreach (var node in item.children) 133 { 134 result = treeitemdofilter(node) || result; 135 } 136 137 return result || item.namecontains(this.filter); 138 } 139 140 private bool treeitemdofilter(treeviewitemvm vm) 141 { 142 if (vm == null) 143 { 144 return true; 145 } 146 147 bool result = false; 148 if (vm.type == nodetype.region || vm.type == nodetype.unit) 149 { 150 foreach (var item in vm.children) 151 { 152 result = treeitemdofilter(item) || result; 153 } 154 } 155 156 if (result || vm.namecontains(this.filter)) 157 { 158 result = true; 159 vm.visible = system.windows.visibility.visible; 160 } 161 else 162 { 163 vm.visible = system.windows.visibility.collapsed; 164 } 165 166 return result; 167 } 168 169 public void inittreeview() 170 { 171 this.view = collectionviewsource.getdefaultview(this.root.children); 172 this.view.filter = this.dofilter; 173 this.refresh(); 174 } 175 } 176 }
3.在界面添加一个treeview,并添加一个简单的style,将viewmodel中必要数据进行绑定:
1 <window x:class="treeviewdemo.mainwindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 title="mainwindow" height="450" width="525"> 5 <window.resources> 6 <style x:key="style" targettype="{x:type treeviewitem}"> 7 <setter property="template"> 8 <setter.value> 9 <controltemplate targettype="{x:type treeviewitem}"> 10 <grid visibility="{binding visible}" background="{binding background}"> 11 <contentpresenter contentsource="header"/> 12 </grid> 13 14 <controltemplate.triggers> 15 <trigger property="isselected" value="true"> 16 <setter property="background" value="green"/> 17 </trigger> 18 </controltemplate.triggers> 19 </controltemplate> 20 </setter.value> 21 </setter> 22 </style> 23 </window.resources> 24 <grid> 25 <grid.rowdefinitions> 26 <rowdefinition height="auto"/> 27 <rowdefinition height="*"/> 28 </grid.rowdefinitions> 29 30 <textbox x:name="searchtxt" width="200" horizontalalignment="center" height="40" 31 margin="20" text="{binding filter, mode=twoway, updatesourcetrigger=propertychanged}"/> 32 33 <treeview 34 grid.row="1" 35 itemssource="{binding view}"> 36 <treeview.itemtemplate> 37 <hierarchicaldatatemplate itemcontainerstyle ="{staticresource style}" itemssource="{binding children}"> 38 <grid height="25" > 39 <textblock 40 x:name="txt" 41 verticalalignment="center" 42 text="{binding displayname}" 43 texttrimming="characterellipsis" 44 tooltip="{binding displayname}" /> 45 </grid> 46 </hierarchicaldatatemplate> 47 </treeview.itemtemplate> 48 </treeview> 49 </grid> 50 </window>
4.在给界面绑定具体的数据
1 using system.windows; 2 3 namespace treeviewdemo 4 { 5 /// <summary> 6 /// mainwindow.xaml 的交互逻辑 7 /// </summary> 8 public partial class mainwindow : window 9 { 10 public mainwindow() 11 { 12 initializecomponent(); 13 this.loaded += mainwindow_loaded; 14 } 15 16 void mainwindow_loaded(object sender, routedeventargs e) 17 { 18 this.datacontext = treeviewviewmodel.instance; 19 } 20 } 21 }
5.运行结果: