最近做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的更多相关文章

  1. winform中ComboBox实现text和value,使显示和值分开,重写text和value属性

    winform的ComboBox中只能赋值text,显示和值是一样的,很多时候不能满足根本需要,熟悉B/S开发的coder最常用的就是text和value分开的,而且web下DropDownList本 ...

  2. C# WinForm 中ComboBox数据绑定的问题 (转)

    来自:http://blog.sina.com.cn/s/blog_5fb9e26301013wga.html C# WinForm 中ComboBox数据绑定的问题 怎样让WinForm中的Comb ...

  3. [C#]WinForm 中 comboBox控件之数据绑定

    [C#]WinForm 中 comboBox控件之数据绑定 一.IList 现在我们直接创建一个List集合,然后绑定 IList<string> list = new List<s ...

  4. winform的comboBox使鼠标滑轮修改值失效

    目标: winform窗体很多combobox下拉框,当他们其中的一个获得焦点的时候,如果滚动鼠标就会改变下拉框的值,要实现让鼠标滚轮不对下拉框的值造成影响 如下代码直接拷贝粘贴,不用修改 方法一: ...

  5. c#(winform)中ComboBox添加Key/Value项、获取选中项、根据Key

    WinForm下的ComboBox默认是以多行文本来设定显示列表的, 这通常不符合大家日常的应用, 因为大家日常应用通常是键/值对的形式去绑定它的. 参考了一些网上的例子,最终写了一个辅助类用于方便对 ...

  6. Winform控件学习-TreeView - ContextMenuStrip

    首先,要向窗体添加一个TreeView控件: 然后再添加一个ContextMenuStrip控件: 接下就要给TreeView添加一个MouseDown事件,代码如下: Example 1 priva ...

  7. WinForm开发中针对TreeView控件改变当前选择节点的字体与颜色

    本文转载:http://www.cnblogs.com/umplatform/archive/2012/08/29/2660240.html 在B/S开发中,对TreeView控件要改变当前选中节点的 ...

  8. C# winform使用combobox遍历文件夹内所有文件

    参考:https://www.cnblogs.com/hxh88/p/5814291.html 相关函数解析: 1.指定目录包含的文件和子目录 DirectoryInfo.GetFiles():获取目 ...

  9. WinForm下ComboBox设定SelectedValue总结 (SelectedValue==null解决办法)[转]

    http://www.cnblogs.com/qqflying/archive/2013/05/23/3096050.html 实践发现:以SelectedIndex赋值让ComboBox自动选中时能 ...

随机推荐

  1. vue入门:用户管理demo

    该demo纯前端实现 使用到vue技术点: 1.在该demo中使用到的vue指令:{{}}. v-if. v-model. @click v-for 2.在该demo中使用到的事件修饰符: .prev ...

  2. UVA 10098 用字典序思想生成所有排列组合

    题目: Generating permutation has always been an important problem in computer science. In this problem ...

  3. GLFW+GLAD OpenGL Mac开发环境搭建

    前言 OpenGL 是什么?The Industry Standard for High Performance Graphics 这是官方解释.说白了他就是一套标准接口.对,是接口,并没有实现具体的 ...

  4. JavaScript数组方法大全(第二篇)

    数组方法大全(第二篇) 注意:如有错误欢迎指出,如有雷同纯属巧合,本博客参考书籍JavaScript权威指南,有兴趣的小伙伴可以去翻阅一下哦 forEach()方法 遍历数组,里面可以传递一个方法 v ...

  5. 什么是W3C??

    为什么想着写这个博客呢,因为最近准备简历去面试,看到好多公司上面都写着熟悉 w3c ,很纳闷,我是一个新手,w3c是什么呢?没听过!!! 所以就去网上查了: 什么是W3C? W3C 万维网联盟(wor ...

  6. 给 asp.net core 写个中间件来记录接口耗时

    给 asp.net core 写个中间件来记录接口耗时 Intro 写接口的难免会遇到别人说接口比较慢,到底慢多少,一个接口服务器处理究竟花了多长时间,如果能有具体的数字来记录每个接口耗时多少,别人再 ...

  7. Codeforces 975D

    题意略. 思路:我们来写一下公式: P1:(x1 + t * Vx1,y1 + t * Vy1)                P2:(x2 + t * Vx2,y2 + t * Vy2) x1 + ...

  8. Keras(五)LSTM 长短期记忆模型 原理及实例

    LSTM 是 long-short term memory 的简称, 中文叫做 长短期记忆. 是当下最流行的 RNN 形式之一 RNN 的弊端 RNN没有长久的记忆,比如一个句子太长时开头部分可能会忘 ...

  9. 写一手好SQL很有必要

    MySQL性能 最大数据量 最大并发数 查询耗时0.5秒 实施原则 数据表设计 数据类型 避免空值 text类型 索引优化 索引分类 优化原则 SQL优化 分批处理 不做列运算 避免Select * ...

  10. codeforces 1041 E. Tree Reconstruction 和度数有关的构造树

    CF 1041E:http://codeforces.com/contest/1041/problem/E 题意: 告诉你一个树的节点个数,显然有n-1条边.已知去掉一条边后,两个集合中最大的节点值. ...