Winform组合ComboBox和TreeView实现ComboTree
最近做Winform项目需要用到类似ComboBox的TreeView控件。
虽然各种第三方控件很多,但是存在各种版本不兼容问题。所以自己写了个简单的ComboTreeView控件。
下图是实现效果:

目前实现的比较简单,能满足我项目中的需求。
此处是项目中的代码简化后的版本,供大家参考。
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();
this.treeView.Padding = new Padding();
this.treeView.AfterExpand += new TreeViewEventHandler(this.WhenAfterExpand); this.treeViewHost = new ToolStripControlHost(this.treeView);
this.treeViewHost.Margin = new Padding();
this.treeViewHost.Padding = new Padding();
this.treeViewHost.AutoSize = false; this.dropDown = new ToolStripDropDown();
this.dropDown.Margin = new Padding();
this.dropDown.Padding = new Padding();
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; } = ; public new int DropDownWidth { get; set; } = ; 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, , 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 = ;
}
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);
}
}
Winform组合ComboBox和TreeView实现ComboTree的更多相关文章
- winform中ComboBox实现text和value,使显示和值分开,重写text和value属性
winform的ComboBox中只能赋值text,显示和值是一样的,很多时候不能满足根本需要,熟悉B/S开发的coder最常用的就是text和value分开的,而且web下DropDownList本 ...
- C# WinForm 中ComboBox数据绑定的问题 (转)
来自:http://blog.sina.com.cn/s/blog_5fb9e26301013wga.html C# WinForm 中ComboBox数据绑定的问题 怎样让WinForm中的Comb ...
- [C#]WinForm 中 comboBox控件之数据绑定
[C#]WinForm 中 comboBox控件之数据绑定 一.IList 现在我们直接创建一个List集合,然后绑定 IList<string> list = new List<s ...
- winform的comboBox使鼠标滑轮修改值失效
目标: winform窗体很多combobox下拉框,当他们其中的一个获得焦点的时候,如果滚动鼠标就会改变下拉框的值,要实现让鼠标滚轮不对下拉框的值造成影响 如下代码直接拷贝粘贴,不用修改 方法一: ...
- c#(winform)中ComboBox添加Key/Value项、获取选中项、根据Key
WinForm下的ComboBox默认是以多行文本来设定显示列表的, 这通常不符合大家日常的应用, 因为大家日常应用通常是键/值对的形式去绑定它的. 参考了一些网上的例子,最终写了一个辅助类用于方便对 ...
- Winform控件学习-TreeView - ContextMenuStrip
首先,要向窗体添加一个TreeView控件: 然后再添加一个ContextMenuStrip控件: 接下就要给TreeView添加一个MouseDown事件,代码如下: Example 1 priva ...
- WinForm开发中针对TreeView控件改变当前选择节点的字体与颜色
本文转载:http://www.cnblogs.com/umplatform/archive/2012/08/29/2660240.html 在B/S开发中,对TreeView控件要改变当前选中节点的 ...
- C# winform使用combobox遍历文件夹内所有文件
参考:https://www.cnblogs.com/hxh88/p/5814291.html 相关函数解析: 1.指定目录包含的文件和子目录 DirectoryInfo.GetFiles():获取目 ...
- WinForm下ComboBox设定SelectedValue总结 (SelectedValue==null解决办法)[转]
http://www.cnblogs.com/qqflying/archive/2013/05/23/3096050.html 实践发现:以SelectedIndex赋值让ComboBox自动选中时能 ...
随机推荐
- Javaweb Cookie机制
Javaweb Cookie机制 一.前言 HTTP协议是一种无状态的协议,WEB服务器本身不能识别出哪些请求是同一个浏览器发出的 ,浏览器的每一次请求都是完全孤立的,即使 HTTP1.1 支持持续连 ...
- Java集合框架之ArrayList浅析
Java集合框架之ArrayList浅析 一.ArrayList综述: 位于java.util包下的ArrayList是java集合框架的重要成员,它就是传说中的动态数组,用MSDN中的说法,就是Ar ...
- python大纲+变量基础详解
1.python的历史 python2和python3的区别 2004 Django框架的诞生 2.python是编程语言 python 是解释型语言 3.python的种类 cpyt ...
- Mybatis基于注解实现多表查询
对应的四种数据库表关系中存在四种关系:一对多,多对应,一对一,多对多.在前文中已经实现了xml配置方式实现表关系的查询,本文记录一下Mybatis怎么通过注解实现多表的查询,算是一个知识的补充. 同样 ...
- 奶牛跟蜗牛,哪种动物智商更高?——T检验帮你找到答案
奶牛跟蜗牛,都是“牛”,那么哪种动物更“牛”,智商更高呢?此时就能用到T检验来找答案~ T 检验(独立样本 T 检验),用于分析定类数据与定量数据之间的关系情况.例如,在本研究中,我们想探究奶牛跟 ...
- node.js的特点与模块化开发
node.js的代码都是构建在模块化开发的基础之上,模块化开始也是node.js的核心之一. node.js跳过了服务器,它自己不用建设在任何服务器软件之上,node.js的许多设计理念与经典架构(L ...
- POJ-3261-Milk Patterns-二分+哈希
Milk Patterns 题意: 在一串数字中,求至少连续k次的最大子序列长度: 思路: 二分加哈希: #include <cstdio> #include <iostream&g ...
- lightoj 1173 - The Vindictive Coach(dp)
题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1173 题解:像这种题目显然可以想到n为几时一共有几种排列可以递推出来.然后就是 ...
- POJ3233 Matrix Power Series 矩阵快速幂 矩阵中的矩阵
Matrix Power Series Time Limit: 3000MS Memory Limit: 131072K Total Submissions: 27277 Accepted: ...
- lightoj 1074 - Extended Traffic(spfa+负环判断)
题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1074 题意:有n个城市,每一个城市有一个拥挤度ai,从一个城市I到另一个城市J ...