我們可以自定義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。
運行代碼,單擊單元格,進入編輯狀態,可以看到如下界面: