• Winform组合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 toBeSelected;
     17 
     18         public ComboTreeView(TreeView internalTreeView)
     19         {
     20             if (null == internalTreeView)
     21             {
     22                 throw new ArgumentNullException("internalTreeView");
     23             }
     24             this.InitializeControls(internalTreeView);
     25         }
     26 
     27         public event TreeNodeChangedEventHandler TreeNodeChanged;
     28 
     29         protected virtual void InitializeControls(TreeView internalTreeView)
     30         {
     31             this.treeView = internalTreeView;
     32             this.treeView.BorderStyle = BorderStyle.FixedSingle;
     33             this.treeView.Margin = new Padding(0);
     34             this.treeView.Padding = new Padding(0);
     35             this.treeView.AfterExpand += new TreeViewEventHandler(this.WhenAfterExpand);
     36 
     37             this.treeViewHost = new ToolStripControlHost(this.treeView);
     38             this.treeViewHost.Margin = new Padding(0);
     39             this.treeViewHost.Padding = new Padding(0);
     40             this.treeViewHost.AutoSize = false;
     41 
     42             this.dropDown = new ToolStripDropDown();
     43             this.dropDown.Margin = new Padding(0);
     44             this.dropDown.Padding = new Padding(0);
     45             this.dropDown.AutoSize = false;
     46             this.dropDown.DropShadowEnabled = true;
     47             this.dropDown.Items.Add(this.treeViewHost);
     48             this.dropDown.Closed += new ToolStripDropDownClosedEventHandler(this.OnDropDownClosed);
     49 
     50             this.DropDownWidth = this.Width;
     51             base.DropDownStyle = ComboBoxStyle.DropDownList;
     52             base.SizeChanged += new EventHandler(this.WhenComboboxSizeChanged);
     53         }
     54 
     55         public new ComboBoxStyle DropDownStyle
     56         {
     57             get { return base.DropDownStyle; }
     58             set { base.DropDownStyle = ComboBoxStyle.DropDownList; }
     59         }
     60 
     61         public virtual TreeNode SelectedNode
     62         {
     63             get { return this.selectedNode; }
     64             private set { this.treeView.SelectedNode = value; }
     65         }
     66 
     67         public virtual T SelectedNodeData
     68         {
     69             get { return (T)base.SelectedItem; }
     70             set
     71             {
     72                 this.toBeSelected = value;
     73                 this.UpdateComboBox(value);
     74             }
     75         }
     76 
     77         protected new int SelectedIndex
     78         {
     79             get { return base.SelectedIndex; }
     80             set { base.SelectedIndex = value; }
     81         }
     82 
     83         protected new object SelectedItem
     84         {
     85             get { return base.SelectedItem; }
     86             set { base.SelectedItem = value; }
     87         }
     88 
     89         public virtual string DisplayMember { get; set; } = "Name";
     90 
     91         /// <summary>Gets the internal TreeView control.</summary>
     92         public virtual TreeView TreeView => this.treeView;
     93 
     94         /// <summary>Gets the collection of tree nodes that are assigned to the tree view control.</summary>
     95         /// <returns>A <see cref="T:System.Windows.Forms.TreeNodeCollection" /> that represents the tree nodes assigned to the tree view control.</returns>
     96         public virtual TreeNodeCollection Nodes => this.treeView.Nodes;
     97 
     98         public new int DropDownHeight { get; set; } = 100;
     99 
    100         public new int DropDownWidth { get; set; } = 100;
    101 
    102         protected virtual void ShowDropDown()
    103         {
    104             this.dropDown.Width = this.Width;
    105             this.dropDown.Height = this.DropDownHeight;
    106             this.treeViewHost.Width = this.Width;
    107             this.treeViewHost.Height = this.DropDownHeight;
    108             this.treeView.Font = this.Font;
    109             this.dropDown.Focus();
    110             this.dropDownOpen = true;
    111             this.dropDown.Show(this, 0, base.Height);
    112         }
    113 
    114         protected virtual void HideDropDown()
    115         {
    116             this.dropDown.Hide();
    117             this.dropDownOpen = false;
    118         }
    119 
    120         protected virtual void ToggleDropDown()
    121         {
    122             if (!this.dropDownOpen)
    123             {
    124                 this.ShowDropDown();
    125             }
    126             else
    127             {
    128                 this.HideDropDown();
    129             }
    130         }
    131 
    132         protected override void WndProc(ref Message m)
    133         {
    134             if ((WM_LBUTTONDOWN == m.Msg) || (WM_LBUTTONDBLCLK == m.Msg))
    135             {
    136                 if (!this.Focused)
    137                 {
    138                     this.Focus();
    139                 }
    140                 this.ToggleDropDown();
    141             }
    142             else
    143             {
    144                 base.WndProc(ref m);
    145             }
    146         }
    147 
    148         protected override void Dispose(bool disposing)
    149         {
    150             if (disposing)
    151             {
    152                 if (this.dropDown != null)
    153                 {
    154                     this.dropDown.Dispose();
    155                     this.dropDown = null;
    156                 }
    157             }
    158             base.Dispose(disposing);
    159         }
    160 
    161         protected virtual void WhenTreeNodeChanged(TreeNode newValue)
    162         {
    163             if ((null != this.selectedNode) || (null != newValue))
    164             {
    165                 bool changed;
    166                 if ((null != this.selectedNode) && (null != newValue))
    167                 {
    168                     changed = (this.selectedNode.GetHashCode() != newValue.GetHashCode());
    169                 }
    170                 else
    171                 {
    172                     changed = true;
    173                 }
    174 
    175                 if (changed)
    176                 {
    177                     if (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                     this.UpdateComboBox(this.GetTreeNodeData(newValue));
    191                 }
    192             }
    193         }
    194 
    195         protected virtual void OnDropDownClosed(object sender, ToolStripDropDownClosedEventArgs e)
    196         {
    197             if (null == this.toBeSelected)
    198             {
    199                 var selectedNode = this.treeView.SelectedNode;
    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 }

    完整项目下载

  • 相关阅读:
    运算符和表达式详解
    超实用的Java web面试题
    80道最新java基础部分面试题(七)
    80道最新java基础部分面试题(六)
    80道最新java基础部分面试题(五)
    12道算法与编程面试题
    javaee和javase的区别
    2019年最新50道java基础部分面试题(四)
    2019年最新50道java基础部分面试题(三)
    2019年最新50道java基础部分面试题(二)
  • 原文地址:https://www.cnblogs.com/yitouniu/p/11589266.html
Copyright © 2020-2023  润新知