【问题标题】:Expose Columns property of a DataGridView in UserControl and make it editable via Designer在 UserControl 中公开 DataGridView 的 Columns 属性并通过设计器使其可编辑
【发布时间】:2016-04-22 07:17:04
【问题描述】:

简短说明:

我有一个带有 DataGridView 的 UserControl。一世 想要将 DataGridView Columns 集合公开给设计器,所以 我可以在设计时更改用户控件上的列。

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

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

我有一个具有以下功能的 UserControl:

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

此用户控件可以自主工作。它有一个供父控件使用的功能:

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

UserControl 引发两个事件:

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

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

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

【问题讨论】:

    标签: c# winforms datagridview user-controls windows-forms-designer


    【解决方案1】:

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

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

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

    为此,我们创建一个包含DataGridViewITypeDescriptorContext 实例,它是Columns 属性,并将其传递给编辑器的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);
        }
    }
    

    【讨论】:

    • 检查过,它可以工作。请注意,您在设计期间添加的列是作为成员添加到表单中的,而不是添加到用户控件中的。幸运的是,在这种情况下我不需要它们。所以我可以将 GenerateMember 设置为 false
    • 感谢您的反馈 :) 我相信这是一种标准行为,因为列属于控件。它与其他控件一样工作,当您将项目添加到集合时,将在表单级别生成集合项目。
    • @RezaAghaei 我已按照您的步骤操作,但我遇到了问题。我创建了一个包含 DataGridView 的用户控件。用户控件具有您指定的 Columns 属性。该项目编译成功,但是当我在包含我的自定义用户控件的表单中进入设计模式并单击 Columns 属性以编辑内容时,它会显示一个消息框,上面写着 No parameterless constructor defined for this object。我在我的用户控件中放入了一个没有参数的公共构造函数,也放入了 CustomColumnEditor 和 TypeDescriptionContext,但它仍然显示相同的消息。
    • @stivex 我再次检查了它,它工作正常。检查您的Columns 属性定义和属性,并将其与我在类中定义的属性进行比较。我首先在用户控件设计表面上放了一个dataGridView1,然后进入代码并添加了用合适的编辑器属性装饰的此类属性。
    • @stivex (3) 您可能会发现this post 和我的回答很有帮助。它描述了自定义网格中的意外行为。
    猜你喜欢
    • 2011-04-12
    • 1970-01-01
    • 1970-01-01
    • 2011-05-09
    • 2017-07-07
    • 1970-01-01
    • 1970-01-01
    • 2011-01-25
    • 1970-01-01
    相关资源
    最近更新 更多