C#控件之TreeComboBox

 初步代码如下:

using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace CustomControl.Tree
{
    public abstract class ComboTreeView<T> : ComboBox where T : class
    {
        protected const int WM_LBUTTONDOWN = 0x0201, WM_LBUTTONDBLCLK = 0x0203;

        protected TreeView treeView;
        protected ToolStripControlHost treeViewHost;
        protected ToolStripDropDown dropDown;
        protected bool dropDownOpen = false;
        protected TreeNode selectedNode;
        protected T toBeSelected;

        public ComboTreeView(TreeView internalTreeView)
        {
            if (null == internalTreeView)
            {
                throw new ArgumentNullException("internalTreeView");
            }
            this.InitializeControls(internalTreeView);
        }

        public event TreeNodeChangedEventHandler TreeNodeChanged;

        protected virtual void InitializeControls(TreeView internalTreeView)
        {
            this.treeView = internalTreeView;
            this.treeView.BorderStyle = BorderStyle.FixedSingle;
            this.treeView.Margin = new Padding(0);
            this.treeView.Padding = new Padding(0);
            this.treeView.AfterExpand += new TreeViewEventHandler(this.WhenAfterExpand);

            this.treeViewHost = new ToolStripControlHost(this.treeView);
            this.treeViewHost.Margin = new Padding(0);
            this.treeViewHost.Padding = new Padding(0);
            this.treeViewHost.AutoSize = false;

            this.dropDown = new ToolStripDropDown();
            this.dropDown.Margin = new Padding(0);
            this.dropDown.Padding = new Padding(0);
            this.dropDown.AutoSize = false;
            this.dropDown.DropShadowEnabled = true;
            this.dropDown.Items.Add(this.treeViewHost);
            this.dropDown.Closed += new ToolStripDropDownClosedEventHandler(this.OnDropDownClosed);

            this.DropDownWidth = this.Width;
            base.DropDownStyle = ComboBoxStyle.DropDownList;
            base.SizeChanged += new EventHandler(this.WhenComboboxSizeChanged);
        }

        public new ComboBoxStyle DropDownStyle
        {
            get { return base.DropDownStyle; }
            set { base.DropDownStyle = ComboBoxStyle.DropDownList; }
        }

        public virtual TreeNode SelectedNode
        {
            get { return this.selectedNode; }
            private set { this.treeView.SelectedNode = value; }
        }

        public virtual T SelectedNodeData
        {
            get { return (T)base.SelectedItem; }
            set
            {
                this.toBeSelected = value;
                this.UpdateComboBox(value);
            }
        }

        protected new int SelectedIndex
        {
            get { return base.SelectedIndex; }
            set { base.SelectedIndex = value; }
        }

        protected new object SelectedItem
        {
            get { return base.SelectedItem; }
            set { base.SelectedItem = value; }
        }

        public virtual string DisplayMember { get; set; } = "Name";

        /// <summary>Gets the internal TreeView control.</summary>
        public virtual TreeView TreeView => this.treeView;

        /// <summary>Gets the collection of tree nodes that are assigned to the tree view control.</summary>
        /// <returns>A <see cref="T:System.Windows.Forms.TreeNodeCollection" /> that represents the tree nodes assigned to the tree view control.</returns>
        public virtual TreeNodeCollection Nodes => this.treeView.Nodes;

        public new int DropDownHeight { get; set; } = 100;

        public new int DropDownWidth { get; set; } = 100;

        protected virtual void ShowDropDown()
        {
            this.dropDown.Width = this.Width;
            this.dropDown.Height = this.DropDownHeight;
            this.treeViewHost.Width = this.Width;
            this.treeViewHost.Height = this.DropDownHeight;
            this.treeView.Font = this.Font;
            this.dropDown.Focus();
            this.dropDownOpen = true;
            this.dropDown.Show(this, 0, base.Height);
        }

        protected virtual void HideDropDown()
        {
            this.dropDown.Hide();
            this.dropDownOpen = false;
        }

        protected virtual void ToggleDropDown()
        {
            if (!this.dropDownOpen)
            {
                this.ShowDropDown();
            }
            else
            {
                this.HideDropDown();
            }
        }

        protected override void WndProc(ref Message m)
        {
            if ((WM_LBUTTONDOWN == m.Msg) || (WM_LBUTTONDBLCLK == m.Msg))
            {
                if (!this.Focused)
                {
                    this.Focus();
                }
                this.ToggleDropDown();
            }
            else
            {
                base.WndProc(ref m);
            }
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (this.dropDown != null)
                {
                    this.dropDown.Dispose();
                    this.dropDown = null;
                }
            }
            base.Dispose(disposing);
        }

        protected virtual void WhenTreeNodeChanged(TreeNode newValue)
        {
            if ((null != this.selectedNode) || (null != newValue))
            {
                bool changed;
                if ((null != this.selectedNode) && (null != newValue))
                {
                    changed = (this.selectedNode.GetHashCode() != newValue.GetHashCode());
                }
                else
                {
                    changed = true;
                }

                if (changed)
                {
                    if (null != this.TreeNodeChanged)
                    {
                        try
                        {
                            this.TreeNodeChanged.Invoke(this, new TreeNodeChangedEventArgs(this.selectedNode, newValue));
                        }
                        catch (Exception)
                        {
                            // do nothing
                        }
                    }

                    this.selectedNode = newValue;
                    this.UpdateComboBox(this.GetTreeNodeData(newValue));
                }
            }
        }

        protected virtual void OnDropDownClosed(object sender, ToolStripDropDownClosedEventArgs e)
        {
            if (null == this.toBeSelected)
            {
                var selectedNode = this.treeView.SelectedNode;
                this.WhenTreeNodeChanged(selectedNode);
            }
        }

        protected virtual void UpdateComboBox(T data)
        {
            base.DisplayMember = this.DisplayMember; // update DisplayMember
            if (null != data)
            {
                this.DataSource = new List<T>() { data };
                this.SelectedIndex = 0;
            }
            else
            {
                this.DataSource = null;
            }
        }

        protected virtual void WhenAfterExpand(object sender, TreeViewEventArgs e)
        {
            if (null != this.toBeSelected)
            {
                if (this.SelectChildNode(e.Node.Nodes, this.toBeSelected))
                {
                    this.toBeSelected = null;
                }
            }
        }

        protected virtual void WhenComboboxSizeChanged(object sender, EventArgs e)
        {
            this.DropDownWidth = base.Width;
        }

        public virtual bool SelectChildNode(TreeNodeCollection nodes, T data)
        {
            var node = this.FindChildNode(nodes, data);
            if (null != node)
            {
                this.DoSelectTreeNode(node);
                return true;
            }
            else
            {
                return false;
            }
        }

        protected abstract bool Identical(T x, T y);

        protected virtual void DoSelectTreeNode(TreeNode node)
        {
            this.SelectedNode = node;
            this.ExpandTreeNode(node.Parent);
        }

        public virtual TreeNode FindChildNode(TreeNodeCollection nodes, T data)
        {
            foreach (TreeNode node in nodes)
            {
                var nodeData = this.GetTreeNodeData(node);
                if (this.Identical(nodeData, data))
                {
                    return node;
                }
            }

            return null;
        }

        public virtual void ExpandTreeNode(TreeNode node)
        {
            if (null != node)
            {
                node.Expand();
                this.ExpandTreeNode(node.Parent);
            }
        }

        public abstract T GetTreeNodeData(TreeNode node);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值