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自动选中时能 ...
随机推荐
- Rest构建分布式 SpringCloud微服务架构项目
一.开发环境:jdk 1.8.Maven 3.x.IDEA 2019.1.4.SpringBoot 2.0.7.spring Cloud 最新的稳定版 Finchley SR2 搭配 ...
- Jesus Is Here[递推]2015沈阳online
题目链接https://nanti.jisuanke.com/t/41175 自从百度之星初赛一上自己做出来一道打表找规律的题之后,这种膨胀的感觉让我近乎丧失理智,今天这道题我死死盯了两三个小时硬是没 ...
- Nginx和Apache各自的优缺点
nginx 相对 apache 的优点: 轻量级,同样起web 服务,比apache 占用更少的内存及资源 抗并发,nginx 处理请求是异步非阻塞的,而apache 则是阻塞型的,在高并发下ngin ...
- Leetcode之回溯法专题-212. 单词搜索 II(Word Search II)
Leetcode之回溯法专题-212. 单词搜索 II(Word Search II) 给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词. 单 ...
- 前端测试工具之 postman
1.不论你是一个前端工程师还是一个后端工程师相信这款工具都会使你的开发更加简便. 2.在此我推荐的一款软件工具是 postman . 在这里我对 postman 做一个简单的介绍: ①它能够模拟表单发 ...
- 网页播放摄像头视频一种新的实现方式(非ocx方式)
前言 出于安全性考虑,浏览器对网页调用本地资源做了诸多限制.单纯的js是不能调用本地摄像头的,最常用的解决方案是通过ocx来实现.ocx是IE浏览器的扩展插件,并不是通用标准,很多浏览器并不支持ocx ...
- Spring Boot2 系列教程(一)纯 Java 搭建 SSM 项目
在 Spring Boot 项目中,正常来说是不存在 XML 配置,这是因为 Spring Boot 不推荐使用 XML ,注意,并非不支持,Spring Boot 推荐开发者使用 Java 配置来搭 ...
- gym/102091
https://codeforces.com/gym/102091 2018-2019 ACM-ICPC, Asia Nakhon Pathom Regional Contest A Flying S ...
- Codeforces 939 D Love Rescue
Love Rescue 题意:Valya 和 Tolya 是一对情侣, 他们的T恤和头巾上都有小写字母,但是女朋友嫌弃男朋友上T恤上的字不和她的头巾上的字一样,就很生气, 然后来了一个魔法师, 它可以 ...
- CodeForces 223C Partial Sums 多次前缀和
Partial Sums 题解: 一个数列多次前缀和之后, 对于第i个数来说他的答案就是 ; i <= n; ++i){ ; j <= i; ++j){ b[i] = (b[i] + 1l ...