我们可以自定义DataGridView的DataGridViewColumn来实现自定义的列,下面介绍一下如何通过扩展DataGridViewColumn来实现一个TreeViewColumn
TreeViewColumn继承自DataGridViewColumn,为了动态给TreeViewColumn传入一个TreeView,这里暴露出一个公共属性_root,可以绑定一个初始化的TreeView. 另外需要重写DataGridCell类型的CellTemplate,这里返还一个TreeViewCell(需要自定义)
1 /// <summary>
2 /// Host TreeView In DataGridView Cell 3 /// </summary>
4 public class TreeViewColumn : DataGridViewColumn 5 { 6 public TreeViewColumn() 7 : base(new TreeViewCell()) 8 { 9 } 10 [Description("Set TreeView Root in DataGridView Cell"), Category("TreeView")] 11 public TreeView _root 12 { 13 get{return Roots.tree;} 14 set{Roots.tree=value;} 15 } 16 public override DataGridViewCell CellTemplate 17 { 18 get
19 { 20 return base.CellTemplate; 21 } 22 set
23 { 24 // Ensure that the cell used for the template is a TreeViewCell.
25 if (value != null &&
26 !value.GetType().IsAssignableFrom(typeof(TreeViewCell))) 27 { 28 throw new InvalidCastException("Must be a TreeViewCell"); 29 } 30 base.CellTemplate = value; 31 } 32 } 33 }
上面TreeViewColumn重写了CellTemplate,返回的就是自定义的TreeViewCell,这里就是具体实现其逻辑。一般来说选择树控件的节点后,返回的是一个文本信息,是文本类型,可以继承DataGridViewTextBoxCell,并重写InitializeEditingControl来进行自定义的DataGridView.EditingControl (编辑控件)。
1 public class TreeViewCell : DataGridViewTextBoxCell 2 { 3
4 public TreeViewCell() 5 : base() 6 { 7
8 //初始设置
9 } 10
11 public override void InitializeEditingControl(int rowIndex, object
12 initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle) 13 { 14 // Set the value of the editing control to the current cell value.
15 base.InitializeEditingControl(rowIndex, initialFormattedValue, 16 dataGridViewCellStyle); 17 TreeViewEditingControl ctl =
18 DataGridView.EditingControl as TreeViewEditingControl; 19 // Use the default row value when Value property is null.
20 if (this.Value == null) 21 { 22
23 ctl.SelectedNode =new TreeNode( this.DefaultNewRowValue.ToString()); 24 } 25 else
26 { 27 ctl.SelectedNode = new TreeNode(this.Value.ToString()); 28 } 29 } 30
31 public override Type EditType 32 { 33 get
34 { 35 // Return the type of the editing control that CalendarCell uses.
36 return typeof(TreeViewEditingControl); 37 } 38 } 39
40 public override Type ValueType 41 { 42 get
43 { 44 // Return the type of the value that CalendarCell contains.
45 return typeof(String); 46 } 47 } 48
49 public override object DefaultNewRowValue 50 { 51 get
52 { 53 // Use the current date and time as the default value.
54 return ""; 55 } 56 } 57 }
TreeViewEditingControl为编辑控件,当用户编辑TreeViewCell时,显示的为树编辑控件,需要继承TreeView,同时实现IDataGridViewEditingControl接口,实现以下方法:
1 public class TreeViewEditingControl : TreeView, IDataGridViewEditingControl 2 { 3 DataGridView dataGridView; 4 private bool valueChanged = false; 5 int rowIndex; 6 public TreeViewEditingControl() 7 { 8 try
9 { 10 //必须加Roots.tree.Nodes[0].Clone() 否则报错 不能在多处增添或插入项,必须首先将其从当前位置移除或将其克隆
11 this.Nodes.Add(Roots.tree.Nodes[0].Clone() as TreeNode); 12 this.SelectedNode = this.Nodes[0]; 13
14
15 } 16 catch (Exception ex) 17 { 18 MessageBox.Show(ex.Message); 19 } 20
21
22 } 23
24 // Implements the IDataGridViewEditingControl.EditingControlFormattedValue 25 // property.
26 public object EditingControlFormattedValue 27 { 28 get
29 { 30 return this.SelectedNode.Text; 31 } 32 set
33 { 34 if (value is String) 35 { 36 try
37 { 38 // This will throw an exception of the string is 39 // null, empty, or not in the format of a date.
40 this.SelectedNode = new TreeNode((String)value); 41
42 } 43 catch
44 { 45 // In the case of an exception, just use the 46 // default value so we're not left with a null 47 // value.
48 this.SelectedNode = new TreeNode(""); 49 } 50 } 51 } 52 } 53
54 // Implements the 55 // IDataGridViewEditingControl.GetEditingControlFormattedValue method.
56 public object GetEditingControlFormattedValue( 57 DataGridViewDataErrorContexts context) 58 { 59 return EditingControlFormattedValue; 60 } 61
62 // Implements the 63 // IDataGridViewEditingControl.ApplyCellStyleToEditingControl method.
64 public void ApplyCellStyleToEditingControl( 65 DataGridViewCellStyle dataGridViewCellStyle) 66 { 67 this.Font = dataGridViewCellStyle.Font; 68 this.ForeColor = dataGridViewCellStyle.ForeColor; 69 this.BackColor = dataGridViewCellStyle.BackColor; 70 } 71
72 // Implements the IDataGridViewEditingControl.EditingControlRowIndex 73 // property.
74 public int EditingControlRowIndex 75 { 76 get
77 { 78 return rowIndex; 79 } 80 set
81 { 82 rowIndex = value; 83 } 84 } 85
86 // Implements the IDataGridViewEditingControl.EditingControlWantsInputKey 87 // method.
88 public bool EditingControlWantsInputKey( 89 Keys key, bool dataGridViewWantsInputKey) 90 { 91 // Let the TreeViewPicker handle the keys listed.
92 switch (key & Keys.KeyCode) 93 { 94 case Keys.Left: 95 case Keys.Up: 96 case Keys.Down: 97 case Keys.Right: 98 case Keys.Home: 99 case Keys.End: 100 case Keys.PageDown: 101 case Keys.PageUp: 102 return true; 103 default: 104 return !dataGridViewWantsInputKey; 105 } 106 } 107
108 // Implements the IDataGridViewEditingControl.PrepareEditingControlForEdit 109 // method.
110 public void PrepareEditingControlForEdit(bool selectAll) 111 { 112 // No preparation needs to be done.
113 } 114
115 // Implements the IDataGridViewEditingControl 116 // .RepositionEditingControlOnValueChange property.
117 public bool RepositionEditingControlOnValueChange 118 { 119 get
120 { 121 return false; 122 } 123 } 124
125 // Implements the IDataGridViewEditingControl 126 // .EditingControlDataGridView property.
127 public DataGridView EditingControlDataGridView 128 { 129 get
130 { 131 return dataGridView; 132 } 133 set
134 { 135 dataGridView = value; 136 } 137 } 138
139 // Implements the IDataGridViewEditingControl 140 // .EditingControlValueChanged property.
141 public bool EditingControlValueChanged 142 { 143 get
144 { 145 return valueChanged; 146 } 147 set
148 { 149 valueChanged = value; 150 } 151 } 152
153 // Implements the IDataGridViewEditingControl 154 // .EditingPanelCursor property.
155 public Cursor EditingPanelCursor 156 { 157 get
158 { 159 return base.Cursor; 160 } 161 } 162
163 protected override void OnAfterExpand(TreeViewEventArgs e) 164 { 165 base.OnAfterExpand(e); 166 this.dataGridView.Columns[this.dataGridView.CurrentCell.ColumnIndex].Width = this.Width+10; 167 this.dataGridView.Rows[this.dataGridView.CurrentCell.RowIndex].Height = this.Height+20; 168
169 } 170 protected override void OnAfterSelect(TreeViewEventArgs e) 171 { 172 // Notify the DataGridView that the contents of the cell 173 // have changed.
174 valueChanged = true; 175 this.EditingControlDataGridView.NotifyCurrentCellDirty(true); 176 base.OnAfterSelect(e); 177
178 } 179
180 }
为了在不同类之间传递参数,定义一个全局静态类:
1 /// <summary>
2 /// 静态类的静态属性,用于在不同class间传递参数 3 /// </summary>
4 public static class Roots 5 { 6 //从前台绑定树
7 public static TreeView tree = null; 8 }
完整代码为:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Windows.Forms; 6 using System.ComponentModel; 7 namespace Host_Controls_in_Windows_Forms_DataGridView_Cells 8 { 9 /// <summary>
10 /// 静态类的静态属性,用于在不同class间传递参数 11 /// </summary>
12 public static class Roots 13 { 14 //从前台绑定树
15 public static TreeView tree = null; 16 } 17 /// <summary>
18 /// Host TreeView In DataGridView Cell 19 /// </summary>
20 public class TreeViewColumn : DataGridViewColumn 21 { 22 public TreeViewColumn() 23 : base(new TreeViewCell()) 24 { 25 } 26 [Description("Set TreeView Root in DataGridView Cell"), Category("TreeView")] 27 public TreeView _root 28 { 29 get{return Roots.tree;} 30 set{Roots.tree=value;} 31 } 32 public override DataGridViewCell CellTemplate 33 { 34 get
35 { 36 return base.CellTemplate; 37 } 38 set
39 { 40 // Ensure that the cell used for the template is a TreeViewCell.
41 if (value != null &&
42 !value.GetType().IsAssignableFrom(typeof(TreeViewCell))) 43 { 44 throw new InvalidCastException("Must be a TreeViewCell"); 45 } 46 base.CellTemplate = value; 47 } 48 } 49 } 50
51 //----------------------------------------------------------------------
52 public class TreeViewCell : DataGridViewTextBoxCell 53 { 54
55 public TreeViewCell() 56 : base() 57 { 58
59 //初始设置
60 } 61
62 public override void InitializeEditingControl(int rowIndex, object
63 initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle) 64 { 65 // Set the value of the editing control to the current cell value.
66 base.InitializeEditingControl(rowIndex, initialFormattedValue, 67 dataGridViewCellStyle); 68 TreeViewEditingControl ctl =
69 DataGridView.EditingControl as TreeViewEditingControl; 70 // Use the default row value when Value property is null.
71 if (this.Value == null) 72 { 73
74 ctl.SelectedNode =new TreeNode( this.DefaultNewRowValue.ToString()); 75 } 76 else
77 { 78 ctl.SelectedNode = new TreeNode(this.Value.ToString()); 79 } 80 } 81
82 public override Type EditType 83 { 84 get
85 { 86 // Return the type of the editing control that CalendarCell uses.
87 return typeof(TreeViewEditingControl); 88 } 89 } 90
91 public override Type ValueType 92 { 93 get
94 { 95 // Return the type of the value that CalendarCell contains.
96 return typeof(String); 97 } 98 } 99
100 public override object DefaultNewRowValue 101 { 102 get
103 { 104 // Use the current date and time as the default value.
105 return ""; 106 } 107 } 108 } 109 //-----------------------------------------------------------------
110
111 public class TreeViewEditingControl : TreeView, IDataGridViewEditingControl 112 { 113 DataGridView dataGridView; 114 private bool valueChanged = false; 115 int rowIndex; 116 public TreeViewEditingControl() 117 { 118 try
119 { 120 //必须加Roots.tree.Nodes[0].Clone() 否则报错 不能在多处增添或插入项,必须首先将其从当前位置移除或将其克隆
121 this.Nodes.Add(Roots.tree.Nodes[0].Clone() as TreeNode); 122 this.SelectedNode = this.Nodes[0]; 123
124
125 } 126 catch (Exception ex) 127 { 128 MessageBox.Show(ex.Message); 129 } 130
131
132 } 133
134 // Implements the IDataGridViewEditingControl.EditingControlFormattedValue 135 // property.
136 public object EditingControlFormattedValue 137 { 138 get
139 { 140 return this.SelectedNode.Text; 141 } 142 set
143 { 144 if (value is String) 145 { 146 try
147 { 148 // This will throw an exception of the string is 149 // null, empty, or not in the format of a date.
150 this.SelectedNode = new TreeNode((String)value); 151
152 } 153 catch
154 { 155 // In the case of an exception, just use the 156 // default value so we're not left with a null 157 // value.
158 this.SelectedNode = new TreeNode(""); 159 } 160 } 161 } 162 } 163
164 // Implements the 165 // IDataGridViewEditingControl.GetEditingControlFormattedValue method.
166 public object GetEditingControlFormattedValue( 167 DataGridViewDataErrorContexts context) 168 { 169 return EditingControlFormattedValue; 170 } 171
172 // Implements the 173 // IDataGridViewEditingControl.ApplyCellStyleToEditingControl method.
174 public void ApplyCellStyleToEditingControl( 175 DataGridViewCellStyle dataGridViewCellStyle) 176 { 177 this.Font = dataGridViewCellStyle.Font; 178 this.ForeColor = dataGridViewCellStyle.ForeColor; 179 this.BackColor = dataGridViewCellStyle.BackColor; 180 } 181
182 // Implements the IDataGridViewEditingControl.EditingControlRowIndex 183 // property.
184 public int EditingControlRowIndex 185 { 186 get
187 { 188 return rowIndex; 189 } 190 set
191 { 192 rowIndex = value; 193 } 194 } 195
196 // Implements the IDataGridViewEditingControl.EditingControlWantsInputKey 197 // method.
198 public bool EditingControlWantsInputKey( 199 Keys key, bool dataGridViewWantsInputKey) 200 { 201 // Let the TreeViewPicker handle the keys listed.
202 switch (key & Keys.KeyCode) 203 { 204 case Keys.Left: 205 case Keys.Up: 206 case Keys.Down: 207 case Keys.Right: 208 case Keys.Home: 209 case Keys.End: 210 case Keys.PageDown: 211 case Keys.PageUp: 212 return true; 213 default: 214 return !dataGridViewWantsInputKey; 215 } 216 } 217
218 // Implements the IDataGridViewEditingControl.PrepareEditingControlForEdit 219 // method.
220 public void PrepareEditingControlForEdit(bool selectAll) 221 { 222 // No preparation needs to be done.
223 } 224
225 // Implements the IDataGridViewEditingControl 226 // .RepositionEditingControlOnValueChange property.
227 public bool RepositionEditingControlOnValueChange 228 { 229 get
230 { 231 return false; 232 } 233 } 234
235 // Implements the IDataGridViewEditingControl 236 // .EditingControlDataGridView property.
237 public DataGridView EditingControlDataGridView 238 { 239 get
240 { 241 return dataGridView; 242 } 243 set
244 { 245 dataGridView = value; 246 } 247 } 248
249 // Implements the IDataGridViewEditingControl 250 // .EditingControlValueChanged property.
251 public bool EditingControlValueChanged 252 { 253 get
254 { 255 return valueChanged; 256 } 257 set
258 { 259 valueChanged = value; 260 } 261 } 262
263 // Implements the IDataGridViewEditingControl 264 // .EditingPanelCursor property.
265 public Cursor EditingPanelCursor 266 { 267 get
268 { 269 return base.Cursor; 270 } 271 } 272
273 protected override void OnAfterExpand(TreeViewEventArgs e) 274 { 275 base.OnAfterExpand(e); 276 this.dataGridView.Columns[this.dataGridView.CurrentCell.ColumnIndex].Width = this.Width+10; 277 this.dataGridView.Rows[this.dataGridView.CurrentCell.RowIndex].Height = this.Height+20; 278
279 } 280 protected override void OnAfterSelect(TreeViewEventArgs e) 281 { 282 // Notify the DataGridView that the contents of the cell 283 // have changed.
284 valueChanged = true; 285 this.EditingControlDataGridView.NotifyCurrentCellDirty(true); 286 base.OnAfterSelect(e); 287
288 } 289
290 } 291
292
293
294 }
当编辑无误后,可以在添加列的时候看到TreeViewColumn类型。此类型暴露出一个_root属性,可以绑定外部的一个带数据的TreeView。
运行代码,单击单元格,进入编辑状态,可以看到如下界面: