我們可以自定義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 }
完整代碼為:


當編輯無誤後,可以在添加列的時候看到TreeViewColumn類型。此類型暴露出一個_root屬性,可以綁定外部的一個帶數據的TreeView。

運行代碼,單擊單元格,進入編輯狀態,可以看到如下界面:
