我们可以自定义DataGridView的DataGridViewColumn来实现自定义的列,下面介绍一下如何通过扩展DataGridViewColumn来实现一个TreeViewColumn
1 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 }
2 TreeViewCell类
上面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 }
3 TreeViewEditingControl类
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。
运行代码,单击单元格,进入编辑状态,可以看到如下界面: