在UserControl中公开DataGridView的Columns属性,并使其可通过Designer进行编辑

简短的介绍:

我有一个带有DataGridView的UserControl。 我想将DataGridView Columns集合暴露给设计器,因此我可以在设计时更改User Control上的列。

问题:我需要哪些设计师属性?

对于那些对较长版本感兴趣的人:

我有一个具有以下function的UserControl:

  • 一个DataGridView,显示集合中项目的“页面”。
  • 一个NumericUpdown控件,用于选择要显示的页面。
  • 页面向上/向下翻页按钮,在显示第一页/最后一页时将禁用
  • 可视地标记对显示项目的更改
  • 用于保存/放弃更改的按钮。

此用户控件可以自动运行。 它有一个由父控件使用的函数:

  • 显示页面(要显示的项目集合)

UserControl引发了两个事件:

  • 事件页面已更改(带有页码)。 应该导致加载新页面
  • 事件保存项目(包含已更改项目的集合)

我必须在几个表单上显示此用户控件。 唯一的区别是DataGridViewColumn的集合因表单而异。

我可以通过编程方式添加列,但使用设计器创建它们会更容易。

通常,使用Editor属性注册合适的UITypeEditor就足够了。 DataGridView使用的编辑器是DataGridViewColumnCollectionEditor 。 但在这种情况下,如果我们直接使用这个编辑器,编辑器希望该属性属于DataGridView并尝试将ITypeDescriptorContext.Instance值转换为DataGridVeiew并且因为我们编辑Columns属性属于我们的用户控件,所以我们将收到一个exception:

无法将“ Type of Control'类型” Type of Control'对象System.Windows.Forms.DataGridView转换为“ System.Windows.Forms.DataGridView ”。

要解决此问题,我们需要创建一个自定义UITypeEditor并覆盖EditValue并编辑用户控件的私有DataGridView字段的Columns属性。

为此,我们创建了一个包含DataGridView及其Columns属性的ITypeDescriptorContext实例,并将其传递给编辑器的EditValue方法。 这样编辑器将编辑我们的Columns属性。

我们还使用[DesignerSerializationVisibility]属性来装饰我们的属性以序列化集合内容。

这是实现。

的MyUserControl

我想你在设计时将一个DataGridView添加到用户控件,它的名称将是dataGridView1

 public partial class MyUserControl : UserControl { public MyUserControl() { InitializeComponent(); } [Editor(typeof(MyColumnEditor), typeof(UITypeEditor))] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public DataGridViewColumnCollection Columns { get { return this.dataGridView1.Columns; } } } 

编辑

 public class MyColumnEditor : UITypeEditor { public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) { return UITypeEditorEditStyle.Modal; } public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) { var field = context.Instance.GetType().GetField("dataGridView1", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); var dataGridView1 = (DataGridView)field.GetValue(context.Instance); dataGridView1.Site = ((Control)context.Instance).Site; var columnsProperty = TypeDescriptor.GetProperties(dataGridView1)["Columns"]; var tdc = new TypeDescriptionContext(dataGridView1, columnsProperty); var editor = (UITypeEditor)columnsProperty.GetEditor(typeof(UITypeEditor)); var result = editor.EditValue(tdc, provider, value); dataGridView1.Site = null; return result; } } 

ITypeDescriptionContext实现

 public class TypeDescriptionContext : ITypeDescriptorContext { private Control editingObject; private PropertyDescriptor editingProperty; public TypeDescriptionContext(Control obj, PropertyDescriptor property) { editingObject = obj; editingProperty = property; } public IContainer Container { get { return editingObject.Container; } } public object Instance { get { return editingObject; } } public void OnComponentChanged() { } public bool OnComponentChanging() { return true; } public PropertyDescriptor PropertyDescriptor { get { return editingProperty; } } public object GetService(Type serviceType) { return editingObject.Site.GetService(serviceType); } }