Winform组合ComboBox和TreeView实现ComboTreeView
程序员文章站
2023-11-26 08:02:09
使用ComboBox和TreeView控件实现下拉树控件ComboTreeView ......
最近做winform项目需要用到类似combobox的treeview控件。
虽然各种第三方控件很多,但是存在各种版本不兼容问题。所以自己写了个简单的combotreeview控件。
下图是实现效果:
目前实现的比较简单,能满足我项目中的需求。
此处是项目中的代码简化后的版本,供大家参考。
1 using system; 2 using system.collections.generic; 3 using system.windows.forms; 4 5 namespace customcontrol.tree 6 { 7 public abstract class combotreeview<t> : combobox where t : class 8 { 9 protected const int wm_lbuttondown = 0x0201, wm_lbuttondblclk = 0x0203; 10 11 protected treeview treeview; 12 protected toolstripcontrolhost treeviewhost; 13 protected toolstripdropdown dropdown; 14 protected bool dropdownopen = false; 15 protected treenode selectednode; 16 protected t selectednodedata; 17 protected t tobeselected; 18 19 public combotreeview(treeview internaltreeview) 20 { 21 if (null == internaltreeview) 22 { 23 throw new argumentnullexception("internaltreeview"); 24 } 25 this.initializecontrols(internaltreeview); 26 } 27 28 public event treenodechangedeventhandler treenodechanged; 29 30 protected virtual void initializecontrols(treeview internaltreeview) 31 { 32 this.treeview = internaltreeview; 33 this.treeview.borderstyle = borderstyle.fixedsingle; 34 this.treeview.margin = new padding(0); 35 this.treeview.padding = new padding(0); 36 this.treeview.afterexpand += new treevieweventhandler(this.whenafterexpand); 37 38 this.treeviewhost = new toolstripcontrolhost(this.treeview); 39 this.treeviewhost.margin = new padding(0); 40 this.treeviewhost.padding = new padding(0); 41 this.treeviewhost.autosize = false; 42 43 this.dropdown = new toolstripdropdown(); 44 this.dropdown.margin = new padding(0); 45 this.dropdown.padding = new padding(0); 46 this.dropdown.autosize = false; 47 this.dropdown.dropshadowenabled = true; 48 this.dropdown.items.add(this.treeviewhost); 49 this.dropdown.closed += new toolstripdropdownclosedeventhandler(this.ondropdownclosed); 50 51 this.dropdownwidth = this.width; 52 base.dropdownstyle = comboboxstyle.dropdownlist; 53 base.sizechanged += new eventhandler(this.whencomboboxsizechanged); 54 } 55 56 public new comboboxstyle dropdownstyle 57 { 58 get { return base.dropdownstyle; } 59 set { base.dropdownstyle = comboboxstyle.dropdownlist; } 60 } 61 62 public virtual treenode selectednode 63 { 64 get { return this.selectednode; } 65 private set { this.treeview.selectednode = value; } 66 } 67 68 public virtual t selectednodedata 69 { 70 get { return this.selectednodedata; } 71 set 72 { 73 this.selectednodedata = value; 74 this.tobeselected = value; 75 this.updatecombobox(value); 76 } 77 } 78 79 protected new int selectedindex 80 { 81 get { return base.selectedindex; } 82 set { base.selectedindex = value; } 83 } 84 85 protected new object selecteditem 86 { 87 get { return base.selecteditem; } 88 set { base.selecteditem = value; } 89 } 90 91 public virtual string displaymember { get; set; } = "name"; 92 93 /// <summary>gets the internal treeview control.</summary> 94 public virtual treeview treeview => this.treeview; 95 96 /// <summary>gets the collection of tree nodes that are assigned to the tree view control.</summary> 97 /// <returns>a <see cref="t:system.windows.forms.treenodecollection" /> that represents the tree nodes assigned to the tree view control.</returns> 98 public virtual treenodecollection nodes => this.treeview.nodes; 99 100 public new int dropdownheight { get; set; } = 100; 101 102 public new int dropdownwidth { get; set; } = 100; 103 104 protected virtual void showdropdown() 105 { 106 this.dropdown.width = this.width; 107 this.dropdown.height = this.dropdownheight; 108 this.treeviewhost.width = this.width; 109 this.treeviewhost.height = this.dropdownheight; 110 this.treeview.font = this.font; 111 this.dropdown.focus(); 112 this.dropdownopen = true; 113 this.dropdown.show(this, 0, base.height); 114 } 115 116 protected virtual void hidedropdown() 117 { 118 this.dropdown.hide(); 119 this.dropdownopen = false; 120 } 121 122 protected virtual void toggledropdown() 123 { 124 if (!this.dropdownopen) 125 { 126 this.showdropdown(); 127 } 128 else 129 { 130 this.hidedropdown(); 131 } 132 } 133 134 protected override void wndproc(ref message m) 135 { 136 if ((wm_lbuttondown == m.msg) || (wm_lbuttondblclk == m.msg)) 137 { 138 if (!this.focused) 139 { 140 this.focus(); 141 } 142 this.toggledropdown(); 143 } 144 else 145 { 146 base.wndproc(ref m); 147 } 148 } 149 150 protected override void dispose(bool disposing) 151 { 152 if (disposing) 153 { 154 if (this.dropdown != null) 155 { 156 this.dropdown.dispose(); 157 this.dropdown = null; 158 } 159 } 160 base.dispose(disposing); 161 } 162 163 protected virtual void whentreenodechanged(treenode newvalue) 164 { 165 if ((null != this.selectednode) || (null != newvalue)) 166 { 167 bool changed; 168 if ((null != this.selectednode) && (null != newvalue)) 169 { 170 changed = (this.selectednode.gethashcode() != newvalue.gethashcode()); 171 } 172 else 173 { 174 changed = true; 175 } 176 177 if (changed && (null != this.treenodechanged)) 178 { 179 try 180 { 181 this.treenodechanged.invoke(this, new treenodechangedeventargs(this.selectednode, newvalue)); 182 } 183 catch (exception) 184 { 185 // do nothing 186 } 187 } 188 189 this.selectednode = newvalue; 190 } 191 } 192 193 protected virtual void ondropdownclosed(object sender, toolstripdropdownclosedeventargs e) 194 { 195 if (null == this.tobeselected) 196 { 197 var selectednode = this.treeview.selectednode; 198 var selecteddata = this.gettreenodedata(selectednode); 199 this.updatecombobox(selecteddata); 200 this.whentreenodechanged(selectednode); 201 } 202 } 203 204 protected virtual void updatecombobox(t data) 205 { 206 base.displaymember = this.displaymember; // update displaymember 207 if (null != data) 208 { 209 this.datasource = new list<t>() { data }; 210 this.selectedindex = 0; 211 } 212 else 213 { 214 this.datasource = null; 215 } 216 } 217 218 protected virtual void whenafterexpand(object sender, treevieweventargs e) 219 { 220 if (null != this.tobeselected) 221 { 222 if (this.selectchildnode(e.node.nodes, this.tobeselected)) 223 { 224 this.tobeselected = null; 225 } 226 } 227 } 228 229 protected virtual void whencomboboxsizechanged(object sender, eventargs e) 230 { 231 this.dropdownwidth = base.width; 232 } 233 234 public virtual bool selectchildnode(treenodecollection nodes, t data) 235 { 236 var node = this.findchildnode(nodes, data); 237 if (null != node) 238 { 239 this.doselecttreenode(node); 240 return true; 241 } 242 else 243 { 244 return false; 245 } 246 } 247 248 protected abstract bool identical(t x, t y); 249 250 protected virtual void doselecttreenode(treenode node) 251 { 252 this.selectednode = node; 253 this.expandtreenode(node.parent); 254 } 255 256 public virtual treenode findchildnode(treenodecollection nodes, t data) 257 { 258 foreach (treenode node in nodes) 259 { 260 var nodedata = this.gettreenodedata(node); 261 if (this.identical(nodedata, data)) 262 { 263 return node; 264 } 265 } 266 267 return null; 268 } 269 270 public virtual void expandtreenode(treenode node) 271 { 272 if (null != node) 273 { 274 node.expand(); 275 this.expandtreenode(node.parent); 276 } 277 } 278 279 public abstract t gettreenodedata(treenode node); 280 } 281 }
上一篇: C#面向对象之多态