我们可以自定义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. JS原生第二篇 (帅哥)

    1.1 Javascript 作用  1.  网页特效 2. 用户交互 3. 表单验证 Js  就是可以用来控制   结构  和 样式 . 1.2  体验js   认识常用的三个输出语句.  都属于 ...

  2. Grunt 安装与配置环境

    当时学习 Grunt 的时候,真是很头疼.分了两个时间段,学习了两次才硬啃下来,之后才能用在项目中.主要原因我认为是学习资料和文档上面写的太高端了.这类的文档或者资料有个显著特点,上来先简单介绍一下这 ...

  3. 元素多层嵌套,JS获取问题

    如果一段html嵌套过多,在js中获取还是比较麻烦的,我写了几套方案,大家可以参考参考,如果你有好的方法,也分享出来,让我们瞧瞧. HTML: <!DOCTYPE html> <ht ...

  4. elastic-job

    github源码: https://github.com/dangdangdotcom/elastic-job maven中央仓: http://repo1.maven.org/maven2/com/ ...

  5. hdu1269迷宫城堡(判断有向图是否是一个强连通图)

    1 /* 题意: 给你一个图,求这个有向图示否是一个强连通图(每两个节点都是可以相互到达的)! 思路1:按正向边dfs一遍,将经过的节点计数,如果记录的节点的个数小于n,那么就说明图按照正向边就不是连 ...

  6. poj 1386 Play on Words(有向图欧拉回路)

    /* 题意:单词拼接,前一个单词的末尾字母和后一个单词的开头字母相同 思路:将一个单词的开头和末尾单词分别做两个点并建一条有向边!然后判断是否存在欧拉回路或者欧拉路 再次强调有向图欧拉路或欧拉回路的判 ...

  7. Cwinux源码解析(四)

    我在我的 薛途的博客 上发表了新的文章,欢迎各位批评指正. Cwinux源码解析(四)

  8. (斐波那契总结)Write a method to generate the nth Fibonacci number (CC150 8.1)

    根据CC150的解决方式和Introduction to Java programming总结: 使用了两种方式,递归和迭代 CC150提供的代码比较简洁,不过某些细节需要分析. 现在直接运行代码,输 ...

  9. Windows Azure Virtual Machine (33) Azure虚拟机删除重建

    <Windows Azure Platform 系列文章目录> 注意:本文介绍的重建Azure虚拟机,必须在同一个订阅内删除重建,必须在同一个订阅内删除重建,必须在同一个订阅内删除重建. ...

  10. JAVA 设计模式 命令模式

    用途 命令模式 (Command) 将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化:对请求排队或请求日志,以及支持可撤销的操作. 命令模式是一种行为型模式. 结构