我们可以自定义DataGridView的DataGridViewColumn来实现自定义的列,下面介绍一下如何通过扩展DataGridViewColumn来实现一个TreeViewColumn

1 TreeViewColumn类

 TreeViewColumn继承自DataGridViewColumn,为了动态给TreeViewColumn传入一个TreeView,这里暴露出一个公共属性_root,可以绑定一个初始化的TreeView. 另外需要重写DataGridCell类型的CellTemplate,这里返还一个TreeViewCell(需要自定义)

     /// <summary>
/// Host TreeView In DataGridView Cell
/// </summary>
public class TreeViewColumn : DataGridViewColumn
{
public TreeViewColumn()
: base(new TreeViewCell())
{
}
[Description("Set TreeView Root in DataGridView Cell"), Category("TreeView")]
public TreeView _root
{
get{return Roots.tree;}
set{Roots.tree=value;}
}
public override DataGridViewCell CellTemplate
{
get
{
return base.CellTemplate;
}
set
{
// Ensure that the cell used for the template is a TreeViewCell.
if (value != null &&
!value.GetType().IsAssignableFrom(typeof(TreeViewCell)))
{
throw new InvalidCastException("Must be a TreeViewCell");
}
base.CellTemplate = value;
}
}
}

2 TreeViewCell类

  上面TreeViewColumn重写了CellTemplate,返回的就是自定义的TreeViewCell,这里就是具体实现其逻辑。一般来说选择树控件的节点后,返回的是一个文本信息,是文本类型,可以继承DataGridViewTextBoxCell,并重写InitializeEditingControl来进行自定义的DataGridView.EditingControl (编辑控件)。

   public class TreeViewCell : DataGridViewTextBoxCell
{ public TreeViewCell()
: base()
{ //初始设置
} public override void InitializeEditingControl(int rowIndex, object
initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
{
// Set the value of the editing control to the current cell value.
base.InitializeEditingControl(rowIndex, initialFormattedValue,
dataGridViewCellStyle);
TreeViewEditingControl ctl =
DataGridView.EditingControl as TreeViewEditingControl;
// Use the default row value when Value property is null.
if (this.Value == null)
{ ctl.SelectedNode =new TreeNode( this.DefaultNewRowValue.ToString());
}
else
{
ctl.SelectedNode = new TreeNode(this.Value.ToString());
}
} public override Type EditType
{
get
{
// Return the type of the editing control that CalendarCell uses.
return typeof(TreeViewEditingControl);
}
} public override Type ValueType
{
get
{
// Return the type of the value that CalendarCell contains.
return typeof(String);
}
} public override object DefaultNewRowValue
{
get
{
// Use the current date and time as the default value.
return "";
}
}
}

3 TreeViewEditingControl类

  TreeViewEditingControl为编辑控件,当用户编辑TreeViewCell时,显示的为树编辑控件,需要继承TreeView,同时实现IDataGridViewEditingControl接口,实现以下方法:

 public class TreeViewEditingControl : TreeView, IDataGridViewEditingControl
{
DataGridView dataGridView;
private bool valueChanged = false;
int rowIndex;
public TreeViewEditingControl()
{
try
{
//必须加Roots.tree.Nodes[0].Clone() 否则报错 不能在多处增添或插入项,必须首先将其从当前位置移除或将其克隆
this.Nodes.Add(Roots.tree.Nodes[].Clone() as TreeNode);
this.SelectedNode = this.Nodes[]; }
catch (Exception ex)
{
MessageBox.Show(ex.Message);
} } // Implements the IDataGridViewEditingControl.EditingControlFormattedValue
// property.
public object EditingControlFormattedValue
{
get
{
return this.SelectedNode.Text;
}
set
{
if (value is String)
{
try
{
// This will throw an exception of the string is
// null, empty, or not in the format of a date.
this.SelectedNode = new TreeNode((String)value); }
catch
{
// In the case of an exception, just use the
// default value so we're not left with a null
// value.
this.SelectedNode = new TreeNode("");
}
}
}
} // Implements the
// IDataGridViewEditingControl.GetEditingControlFormattedValue method.
public object GetEditingControlFormattedValue(
DataGridViewDataErrorContexts context)
{
return EditingControlFormattedValue;
} // Implements the
// IDataGridViewEditingControl.ApplyCellStyleToEditingControl method.
public void ApplyCellStyleToEditingControl(
DataGridViewCellStyle dataGridViewCellStyle)
{
this.Font = dataGridViewCellStyle.Font;
this.ForeColor = dataGridViewCellStyle.ForeColor;
this.BackColor = dataGridViewCellStyle.BackColor;
} // Implements the IDataGridViewEditingControl.EditingControlRowIndex
// property.
public int EditingControlRowIndex
{
get
{
return rowIndex;
}
set
{
rowIndex = value;
}
} // Implements the IDataGridViewEditingControl.EditingControlWantsInputKey
// method.
public bool EditingControlWantsInputKey(
Keys key, bool dataGridViewWantsInputKey)
{
// Let the TreeViewPicker handle the keys listed.
switch (key & Keys.KeyCode)
{
case Keys.Left:
case Keys.Up:
case Keys.Down:
case Keys.Right:
case Keys.Home:
case Keys.End:
case Keys.PageDown:
case Keys.PageUp:
return true;
default:
return !dataGridViewWantsInputKey;
}
} // Implements the IDataGridViewEditingControl.PrepareEditingControlForEdit
// method.
public void PrepareEditingControlForEdit(bool selectAll)
{
// No preparation needs to be done.
} // Implements the IDataGridViewEditingControl
// .RepositionEditingControlOnValueChange property.
public bool RepositionEditingControlOnValueChange
{
get
{
return false;
}
} // Implements the IDataGridViewEditingControl
// .EditingControlDataGridView property.
public DataGridView EditingControlDataGridView
{
get
{
return dataGridView;
}
set
{
dataGridView = value;
}
} // Implements the IDataGridViewEditingControl
// .EditingControlValueChanged property.
public bool EditingControlValueChanged
{
get
{
return valueChanged;
}
set
{
valueChanged = value;
}
} // Implements the IDataGridViewEditingControl
// .EditingPanelCursor property.
public Cursor EditingPanelCursor
{
get
{
return base.Cursor;
}
} protected override void OnAfterExpand(TreeViewEventArgs e)
{
base.OnAfterExpand(e);
this.dataGridView.Columns[this.dataGridView.CurrentCell.ColumnIndex].Width = this.Width+;
this.dataGridView.Rows[this.dataGridView.CurrentCell.RowIndex].Height = this.Height+; }
protected override void OnAfterSelect(TreeViewEventArgs e)
{
// Notify the DataGridView that the contents of the cell
// have changed.
valueChanged = true;
this.EditingControlDataGridView.NotifyCurrentCellDirty(true);
base.OnAfterSelect(e); } }

  为了在不同类之间传递参数,定义一个全局静态类:

   /// <summary>
/// 静态类的静态属性,用于在不同class间传递参数
/// </summary>
public static class Roots
{
//从前台绑定树
public static TreeView tree = null;
}

完整代码为:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
namespace Host_Controls_in_Windows_Forms_DataGridView_Cells
{
/// <summary>
/// 静态类的静态属性,用于在不同class间传递参数
/// </summary>
public static class Roots
{
//从前台绑定树
public static TreeView tree = null;
}
/// <summary>
/// Host TreeView In DataGridView Cell
/// </summary>
public class TreeViewColumn : DataGridViewColumn
{
public TreeViewColumn()
: base(new TreeViewCell())
{
}
[Description("Set TreeView Root in DataGridView Cell"), Category("TreeView")]
public TreeView _root
{
get{return Roots.tree;}
set{Roots.tree=value;}
}
public override DataGridViewCell CellTemplate
{
get
{
return base.CellTemplate;
}
set
{ // Ensure that the cell used for the template is a TreeViewCell.
if (value != null &&
!value.GetType().IsAssignableFrom(typeof(TreeViewCell)))
{
throw new InvalidCastException("Must be a TreeViewCell");
}
base.CellTemplate = value;
}
}
} //----------------------------------------------------------------------
public class TreeViewCell : DataGridViewTextBoxCell
{ public TreeViewCell()
: base()
{ //初始设置
} public override void InitializeEditingControl(int rowIndex, object
initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
{
// Set the value of the editing control to the current cell value.
base.InitializeEditingControl(rowIndex, initialFormattedValue,
dataGridViewCellStyle);
TreeViewEditingControl ctl =
DataGridView.EditingControl as TreeViewEditingControl;
// Use the default row value when Value property is null.
if (this.Value == null)
{ ctl.SelectedNode =new TreeNode( this.DefaultNewRowValue.ToString());
}
else
{
ctl.SelectedNode = new TreeNode(this.Value.ToString());
}
} public override Type EditType
{
get
{
// Return the type of the editing control that CalendarCell uses.
return typeof(TreeViewEditingControl);
}
} public override Type ValueType
{
get
{
// Return the type of the value that CalendarCell contains.
return typeof(String);
}
} public override object DefaultNewRowValue
{
get
{
// Use the current date and time as the default value.
return "";
}
}
}
//----------------------------------------------------------------- public class TreeViewEditingControl : TreeView, IDataGridViewEditingControl
{
DataGridView dataGridView;
private bool valueChanged = false;
int rowIndex;
public TreeViewEditingControl()
{
try
{
//必须加Roots.tree.Nodes[0].Clone() 否则报错 不能在多处增添或插入项,必须首先将其从当前位置移除或将其克隆
this.Nodes.Add(Roots.tree.Nodes[].Clone() as TreeNode);
this.SelectedNode = this.Nodes[]; }
catch (Exception ex)
{
MessageBox.Show(ex.Message);
} } // Implements the IDataGridViewEditingControl.EditingControlFormattedValue
// property.
public object EditingControlFormattedValue
{
get
{
return this.SelectedNode.Text;
}
set
{
if (value is String)
{
try
{
// This will throw an exception of the string is
// null, empty, or not in the format of a date.
this.SelectedNode = new TreeNode((String)value); }
catch
{
// In the case of an exception, just use the
// default value so we're not left with a null
// value.
this.SelectedNode = new TreeNode("");
}
}
}
} // Implements the
// IDataGridViewEditingControl.GetEditingControlFormattedValue method.
public object GetEditingControlFormattedValue(
DataGridViewDataErrorContexts context)
{
return EditingControlFormattedValue;
} // Implements the
// IDataGridViewEditingControl.ApplyCellStyleToEditingControl method.
public void ApplyCellStyleToEditingControl(
DataGridViewCellStyle dataGridViewCellStyle)
{
this.Font = dataGridViewCellStyle.Font;
this.ForeColor = dataGridViewCellStyle.ForeColor;
this.BackColor = dataGridViewCellStyle.BackColor;
} // Implements the IDataGridViewEditingControl.EditingControlRowIndex
// property.
public int EditingControlRowIndex
{
get
{
return rowIndex;
}
set
{
rowIndex = value;
}
} // Implements the IDataGridViewEditingControl.EditingControlWantsInputKey
// method.
public bool EditingControlWantsInputKey(
Keys key, bool dataGridViewWantsInputKey)
{
// Let the TreeViewPicker handle the keys listed.
switch (key & Keys.KeyCode)
{
case Keys.Left:
case Keys.Up:
case Keys.Down:
case Keys.Right:
case Keys.Home:
case Keys.End:
case Keys.PageDown:
case Keys.PageUp:
return true;
default:
return !dataGridViewWantsInputKey;
}
} // Implements the IDataGridViewEditingControl.PrepareEditingControlForEdit
// method.
public void PrepareEditingControlForEdit(bool selectAll)
{
// No preparation needs to be done.
} // Implements the IDataGridViewEditingControl
// .RepositionEditingControlOnValueChange property.
public bool RepositionEditingControlOnValueChange
{
get
{
return false;
}
} // Implements the IDataGridViewEditingControl
// .EditingControlDataGridView property.
public DataGridView EditingControlDataGridView
{
get
{
return dataGridView;
}
set
{
dataGridView = value;
}
} // Implements the IDataGridViewEditingControl
// .EditingControlValueChanged property.
public bool EditingControlValueChanged
{
get
{
return valueChanged;
}
set
{
valueChanged = value;
}
} // Implements the IDataGridViewEditingControl
// .EditingPanelCursor property.
public Cursor EditingPanelCursor
{
get
{
return base.Cursor;
}
} protected override void OnAfterExpand(TreeViewEventArgs e)
{
base.OnAfterExpand(e);
this.dataGridView.Columns[this.dataGridView.CurrentCell.ColumnIndex].Width = this.Width+;
this.dataGridView.Rows[this.dataGridView.CurrentCell.RowIndex].Height = this.Height+; }
protected override void OnAfterSelect(TreeViewEventArgs e)
{
// Notify the DataGridView that the contents of the cell
// have changed.
valueChanged = true;
this.EditingControlDataGridView.NotifyCurrentCellDirty(true);
base.OnAfterSelect(e); } } }

  当编辑无误后,可以在添加列的时候看到TreeViewColumn类型。此类型暴露出一个_root属性,可以绑定外部的一个带数据的TreeView。

  运行代码,单击单元格,进入编辑状态,可以看到如下界面:

C#如何自定义DataGridViewColumn来显示TreeView的更多相关文章

  1. ToastUtil【简单的Toast封装类】【未自定义Toast的显示风格】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 一个简单的Toast封装类. 效果图 API = 6.0 API = 4.4.2 代码分析 实现了不管我们触发多少次Toast调用, ...

  2. ToastCustomUtil【简单的Toast封装类】【自定义Toast的显示风格】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 ToastUtil + ToastCustom结合.主要解决低版本机型上系统toast显示不好看的问题. 效果图 代码分析 在Toa ...

  3. iOS8自定义推送显示按钮及推送优化

    http://www.jianshu.com/p/803bfaae989e iOS8自定义推送显示按钮及推送优化 字数1435 阅读473 评论0 喜欢2 导语 在iOS8中,推送消息不再只是简单地点 ...

  4. WPF自定义窗口最大化显示任务栏

    原文:WPF自定义窗口最大化显示任务栏 当我们要自定义WPF窗口样式时,通常是采用设计窗口的属性 WindowStyle="None" ,然后为窗口自定义放大,缩小,关闭按钮的样式 ...

  5. Django(四) 后台管理:创建管理员、注册模型类、自定义管理页面显示内容

    后台管理 第1步.本地化:设置语言.时区 修改project1/settings.py #LANGUAGE_CODE = 'en-us' LANGUAGE_CODE = 'zh-hans' #设置语言 ...

  6. 怎么自定义DataGridViewColumn(日期列,C#)

    参考:https://msdn.microsoft.com/en-us/library/7tas5c80.aspx 未解决的问题:如果日期要设置为null,怎么办? DataGridView控件提供了 ...

  7. 调试asp.net网页时不显示treeview的原因

    在.net中本地调试asp.net网页时,treeview控件显示为文字方式,原因是在http://localhost/下面找不到webctrl_client的路径,解决的方法是把webctrl_cl ...

  8. yii2-basic后台管理功能开发之三:自定义GridView列显示

    在第二篇 yii2-basic后台管理功能开发之二:创建CRUD增删改查 中,我们利用gii工具生成的结果一般并不是我们想要的结果. 我们需要根据自己的需求自定义列显示.我遇到的主要是一下变更: 时间 ...

  9. 自定义一个只显示年月的DatePicker(UIDatePicker无法实现年月显示)

    HooDatePicker 介绍(introduction) ==================================================项目需要一个DatePicker,只显 ...

随机推荐

  1. CSS两列高度自适应,右边自适应

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. Socket实现仿QQ聊天(可部署于广域网)附源码(1)-简介

    1.前言 本次实现的这个聊天工具是我去年c#程序设计课程所写的Socket仿QQ聊天,由于当时候没有自己的服务器,只能在机房局域网内进行测试,最近在腾讯云上买了一台云主机(本人学生党,腾讯云有个学生专 ...

  3. RAC Concept

    1. RAC的高可用性 RAC的高可用性主要包含以下几点: 1> 实现节点间的负载均衡. 2> 实现失败切换的功能. 3> 通过Service组件来控制客户端的访问路径. 4> ...

  4. 安装android studio报错Failed to install Intel HAXM.

    在安装android studio的过程中,安装到android的模拟器加速器(intel HAXM)这一步时,报错: HAXM是用来管理硬件加速的,估计是用了这个东西模拟器就能告别Eclipse的龟 ...

  5. JS根据身份证号码算年龄

    如果把身份证号码传到页面上,在前端页面获取年龄就需要用到JS脚本了: function GetAge(identityCard) { var len = (identityCard + "& ...

  6. 我们一起来动手开发一个Orm框架,开源发布

    我们追求的方向 1)高性能. 这也是架构创建的目的之一,已经将它的性能提升到了极致.大家可以自己测试.我可以说其性能是数一数二的.连接地址:Moon洗冤录 2)易用性强 我想,用过Moon.ORM的应 ...

  7. RegularHelper

    private const string m_NumberPattm = @"^[-+]?(0{1}|(([1-9]){1}[0-9]{0,6}))?$"; private con ...

  8. [python基础]关于包,类,模块的那些事儿

    转载请注明出处:http://www.cnblogs.com/codefish/p/5032753.html 在理解python的包,类,模块之前,我一直是将他类比为dll,C#的类,命名空间的这种参 ...

  9. html5的canvas绘制迷宫地图

    canvas标签一直是html5的亮点,用它可以实现很多东西.我想用它来绘画像迷宫那样的地图.借助到的工具有瓦片地图编辑器tiled(点击跳转到下载链接). 如图:如果你想要画像这样的迷宫地图,如果不 ...

  10. JavaScript的setTimeout和setInterval的深入理解

    发表过一片博客<跟着我用JavaScript写计时器>,比较基础.....有网友说应该写一下setTimeout的原理和机制,嗯,今天就来写一下吧: 直奔主题:setTimeout和set ...