- 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 }