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自动选中时能 ...
随机推荐
- Nginx+Zuul集群实现高可用网关
代码参考:https://github.com/HCJ-shadow/Zuul-Gateway-Cluster-Nginx Zuul的路由转发功能 前期准备 搭建Eureka服务注册中心 服务提供者m ...
- Springboot源码分析之AbstractAdvisorAutoProxyCreator
摘要: Spring的代理在上层中主要分为ProxyCreatorSupport和ProxyProcessorSupport,前者是基于代理工厂,后者是基于后置处理器,也可以认为后置就是自动代理器.当 ...
- springBoot配置elasticsearch搜索
1.本地安装elasticsearch服务,具体过程见上一篇文章(安装和配置elasticsearch服务集群) 2.修改项目中pom文件,引入搜索相关jar包 <!-- elasticsear ...
- CENTOS服务器基础教程-U盘系统盘制作
什么都要用到一点点,会一点点,现在的USB3.0基本上服务器都已经支持.小编给大家介绍基础篇:如何使用U盘制作系统安装盘 工具/原料 U盘 UltraISO工具 方法/步骤 准备一个U ...
- javascript之操作数组方法
掌握如何操作数组,会让你的开发变得更加高效 1.栈和队列方法(以下四个方法都改变原数组) arr.push() //接受任意类型的参数,逐个添加到数组的末尾,并返回数组的长度 改变原数组 arr.po ...
- 感受一下.net中用 lambda与 linq 做数据集过滤的不同
lambda: ids.Add( _hahahacontext .hahahamodel .FirstOrDefault( a => //lambda做过滤 a.name == "张宏 ...
- F-maximum clique 1_2019牛客暑期多校训练营(第五场)
题意 给出n个不同的数字\(a_i\),求出最大的子集,使得子集内任意两个数在二进制下至少有两位不同. 题解 先对任意两个二进制位只有一个不同的两个数连边,那么问题就转化成找出最多的点集,任意两点没有 ...
- SPOJ - VFMUL - Very Fast Multiplication FFT加速高精度乘法
SPOJ - VFMUL:https://vjudge.net/problem/SPOJ-VFMUL 这是一道FFT求高精度的模板题. 参考:https://www.cnblogs.com/Rabbi ...
- CodeForces 785 D Anton and School - 2 范德蒙恒等式
Anton and School - 2 题解: 枚举每个左括号作为必选的. 那么方案数就应该是下面的 1 , 然后不断化简, 通过范德蒙恒等式 , 可以将其化为一个组合数. 代码: #include ...
- CodeForces 601B Lipshitz Sequence
Lipshitz Sequence 题解: 可以通过观察得到,对于任意一个区间来说, 只有相邻的2个点的差值才会是区间的最大值. 具体观察方法,可以用数学分析, 我是通过画图得到的. 那么基于上面的观 ...