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自动选中时能 ...
随机推荐
- vue入门:用户管理demo
该demo纯前端实现 使用到vue技术点: 1.在该demo中使用到的vue指令:{{}}. v-if. v-model. @click v-for 2.在该demo中使用到的事件修饰符: .prev ...
- UVA 10098 用字典序思想生成所有排列组合
题目: Generating permutation has always been an important problem in computer science. In this problem ...
- GLFW+GLAD OpenGL Mac开发环境搭建
前言 OpenGL 是什么?The Industry Standard for High Performance Graphics 这是官方解释.说白了他就是一套标准接口.对,是接口,并没有实现具体的 ...
- JavaScript数组方法大全(第二篇)
数组方法大全(第二篇) 注意:如有错误欢迎指出,如有雷同纯属巧合,本博客参考书籍JavaScript权威指南,有兴趣的小伙伴可以去翻阅一下哦 forEach()方法 遍历数组,里面可以传递一个方法 v ...
- 什么是W3C??
为什么想着写这个博客呢,因为最近准备简历去面试,看到好多公司上面都写着熟悉 w3c ,很纳闷,我是一个新手,w3c是什么呢?没听过!!! 所以就去网上查了: 什么是W3C? W3C 万维网联盟(wor ...
- 给 asp.net core 写个中间件来记录接口耗时
给 asp.net core 写个中间件来记录接口耗时 Intro 写接口的难免会遇到别人说接口比较慢,到底慢多少,一个接口服务器处理究竟花了多长时间,如果能有具体的数字来记录每个接口耗时多少,别人再 ...
- Codeforces 975D
题意略. 思路:我们来写一下公式: P1:(x1 + t * Vx1,y1 + t * Vy1) P2:(x2 + t * Vx2,y2 + t * Vy2) x1 + ...
- Keras(五)LSTM 长短期记忆模型 原理及实例
LSTM 是 long-short term memory 的简称, 中文叫做 长短期记忆. 是当下最流行的 RNN 形式之一 RNN 的弊端 RNN没有长久的记忆,比如一个句子太长时开头部分可能会忘 ...
- 写一手好SQL很有必要
MySQL性能 最大数据量 最大并发数 查询耗时0.5秒 实施原则 数据表设计 数据类型 避免空值 text类型 索引优化 索引分类 优化原则 SQL优化 分批处理 不做列运算 避免Select * ...
- codeforces 1041 E. Tree Reconstruction 和度数有关的构造树
CF 1041E:http://codeforces.com/contest/1041/problem/E 题意: 告诉你一个树的节点个数,显然有n-1条边.已知去掉一条边后,两个集合中最大的节点值. ...