你的位置:首页 > ASP.net教程

[ASP.net教程]C#如何自定义DataGridViewColumn来显示TreeView


  我们可以自定义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 _root12     {13       get{return Roots.tree;}14       set{Roots.tree=value;}15     }16     public override DataGridViewCell CellTemplate17     {18       get19       {20         return base.CellTemplate;21       }22       set23       {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, object12       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       else26       {27         ctl.SelectedNode = new TreeNode(this.Value.ToString());28       }29     }30 31     public override Type EditType32     {33       get34       {35         // Return the type of the editing control that CalendarCell uses.36         return typeof(TreeViewEditingControl);37       }38     }39 40     public override Type ValueType41     {42       get43       {44         // Return the type of the value that CalendarCell contains.45         return typeof(String);46       }47     }48 49     public override object DefaultNewRowValue50     {51       get52       {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 IDataGridViewEditingControl116     // .RepositionEditingControlOnValueChange property.117     public bool RepositionEditingControlOnValueChange118     {119       get120       {121         return false;122       }123     }124 125     // Implements the IDataGridViewEditingControl126     // .EditingControlDataGridView property.127     public DataGridView EditingControlDataGridView128     {129       get130       {131         return dataGridView;132       }133       set134       {135         dataGridView = value;136       }137     }138 139     // Implements the IDataGridViewEditingControl140     // .EditingControlValueChanged property.141     public bool EditingControlValueChanged142     {143       get144       {145         return valueChanged;146       }147       set148       {149         valueChanged = value;150       }151     }152 153     // Implements the IDataGridViewEditingControl154     // .EditingPanelCursor property.155     public Cursor EditingPanelCursor156     {157       get158       {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 cell173       // 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 Roots5   {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 DefaultNewRowValue101     {102       get103       {104         // Use the current date and time as the default value.105         return "";106       }107     }108   }109   //-----------------------------------------------------------------110 111  public class TreeViewEditingControl : TreeView, IDataGridViewEditingControl112   {113     DataGridView dataGridView;114     private bool valueChanged = false;115     int rowIndex;116     public TreeViewEditingControl()117     {118       try119       {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 EditingControlFormattedValue137     {138       get139       {140         return this.SelectedNode.Text;141       }142       set143       {144         if (value is String)145         {146           try147           {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           catch154           {155             // In the case of an exception, just use the 156             // default value so we're not left with a null157             // 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 EditingControlRowIndex185     {186       get187       {188         return rowIndex;189       }190       set191       {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 IDataGridViewEditingControl226     // .RepositionEditingControlOnValueChange property.227     public bool RepositionEditingControlOnValueChange228     {229       get230       {231         return false;232       }233     }234 235     // Implements the IDataGridViewEditingControl236     // .EditingControlDataGridView property.237     public DataGridView EditingControlDataGridView238     {239       get240       {241         return dataGridView;242       }243       set244       {245         dataGridView = value;246       }247     }248 249     // Implements the IDataGridViewEditingControl250     // .EditingControlValueChanged property.251     public bool EditingControlValueChanged252     {253       get254       {255         return valueChanged;256       }257       set258       {259         valueChanged = value;260       }261     }262 263     // Implements the IDataGridViewEditingControl264     // .EditingPanelCursor property.265     public Cursor EditingPanelCursor266     {267       get268       {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 cell283       // have changed.284       valueChanged = true;285       this.EditingControlDataGridView.NotifyCurrentCellDirty(true);286       base.OnAfterSelect(e);287       288     }289    290   }291 292 293 294 }

View Code

  当编辑无误后,可以在添加列的时候看到TreeViewColumn类型。此类型暴露出一个_root属性,可以绑定外部的一个带数据的TreeView。

  运行代码,单击单元格,进入编辑状态,可以看到如下界面: