在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); } }