Winform组合ComboBox和TreeView实现ComboTree

匿名 (未验证) 提交于 2019-12-02 22:09:29

最近做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 }

完整项目下载

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!