【问题标题】:Designer doesn't serialzie Columns of a DataGridView property of a UserControl设计器不序列化 UserControl 的 DataGridView 属性的列
【发布时间】:2020-12-24 16:10:28
【问题描述】:

我正在尝试创建一个包含标签、工具条和 Datagridview 的自定义控件。

当测试表单生成设计代码时,它会正确保存工具条项,但不会保存 Datagridview 列。 代码 DGrid.cs

...
    [DesignerAttribute(typeof(MultiDesigner))]
    public partial class FDGrid : Panel
    {
        ....
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [Category("Bars"), Description("Barra dei comandi.")]
        public ToolStrip Barra
        {
            get { return _barra; }
            set { _barra = value; }
        }
        
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [Category("Grid"), Description("Griglia dati.")]
        public DataGridView Griglia
        {
            get { return _griglia; }
            set { _griglia = value; }
        }
        ....
        
    }
    
    [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = 
        "FullTrust")]
    public class MultiDesigner : System.Windows.Forms.Design.ControlDesigner
    {
        public override void Initialize(IComponent c)
        {
            base.Initialize(c);
            FDGrid ctl = (FDGrid)c;
            EnableDesignMode(ctl.Griglia, "Griglia");
            EnableDesignMode(ctl.Barra, "Barra");
        }
    }
...

代码 FDGrid.Designer.cs

FDGrid.Designer.cs ....

private FDLabeledImage _titolo;
private ToolStrip _barra;
private DataGridView _griglia;
    

private void InitializeComponent()
{
    this._barra = new System.Windows.Forms.ToolStrip();
    this._griglia = new System.Windows.Forms.DataGridView();
    this._titolo = new FDControl.FDLabeledImage();
    ((System.ComponentModel.ISupportInitialize)(this._griglia)).BeginInit();
    this.SuspendLayout();
    ....
    ((System.ComponentModel.ISupportInitialize)(this._griglia)).EndInit();
    this.ResumeLayout(false);
}

....

代码 Form1.Designer.cs

....    
            
            private void InitializeComponent()
            {
                this.fdGrid1 = new FDControl.FDGrid();  // OK
                this.fdGrid1.Column1 = new System.Windows.Forms.DataGridViewTextBoxColumn(); **// Error** 
                this.toolStripLabel1 = new System.Windows.Forms.ToolStripLabel(); //OK
                
            }
            
            ...
            private FDControl.FDGrid fdGrid1; //OK
            private System.Windows.Forms.ToolStripLabel toolStripLabel1; //OK
            private System.Windows.Forms.DataGridViewTextBoxColumnfdGrid1.Column1;//Error
...

求助,我想知道我哪里错了?

【问题讨论】:

    标签: c# .net winforms components windows-forms-designer


    【解决方案1】:

    不是最优雅的,但可行的解决方案:

    1. 创建一个派生自DataGridView 的自定义MyDataGridView

       using System;
       using System.ComponentModel;
       using System.ComponentModel.Design;
       using System.Drawing.Design;
       using System.Reflection;
       using System.Windows.Forms;
       using System.Windows.Forms.Design;
       public class MyDataGridView : DataGridView
       {
           [Editor(typeof(ExtendedDataGridViewColumnCollectionEditor), typeof(UITypeEditor))]
           public new DataGridViewColumnCollection Columns { get => base.Columns; }
      
           private class ExtendedDataGridViewColumnCollectionEditor : UITypeEditor
           {
               private Form dataGridViewColumnCollectionDialog;
               private ExtendedDataGridViewColumnCollectionEditor() { }
               private static Form CreateColumnCollectionDialog(IServiceProvider provider)
               {
                   var assembly = Assembly.Load(typeof(ControlDesigner).Assembly.ToString());
                   var type = assembly.GetType("System.Windows.Forms.Design.DataGridViewColumnCollectionDialog");
                   var ctor = type.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0];
                   return (Form)ctor.Invoke(new object[] { provider });
               }
               public static void SetLiveDataGridView(Form form, DataGridView dgv)
               {
                   var method = form.GetType().GetMethod("SetLiveDataGridView", BindingFlags.NonPublic | BindingFlags.Instance);
                   method.Invoke(form, new object[] { dgv });
               }
               public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
               {
                   if (provider != null && context != null)
                   {
                       var service = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
                       if (service == null || context.Instance == null)
                           return value;
      
                       var host = (IDesignerHost)provider.GetService(typeof(IDesignerHost));
                       if (host == null)
                           return value;
      
                       if (dataGridViewColumnCollectionDialog == null)
                           dataGridViewColumnCollectionDialog = CreateColumnCollectionDialog(provider);
      
                       var dgv = ((MyDataGridView)context.Instance);
                       var oldSite = dgv.Site;
                       dgv.Site = ((MyDataGridView)context.Instance).Parent?.Site;
                       SetLiveDataGridView(dataGridViewColumnCollectionDialog, dgv);
      
                       using (var transaction = host.CreateTransaction("DataGridViewColumnCollectionTransaction"))
                       {
                           if (service.ShowDialog(dataGridViewColumnCollectionDialog) == DialogResult.OK)
                               transaction.Commit();
                           else
                               transaction.Cancel();
                       }
                       dgv.Site = oldSite;
                   }
                   return value;
               }
               public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
               {
                   return UITypeEditorEditStyle.Modal;
               }
           }
       }
      
    2. 构建解决方案。

    3. 创建您的UserControl 并在其上放置MyDataGridView 的实例。

    4. 公开DataGridView 属性:

       public partial class MyUserControl : UserControl
       {
           public MyUserControl()
           {
               InitializeComponent();
           }
           [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
           public DataGridView DataGridView { get => dataGridView1; }
       }
      
    5. 构建解决方案。

    6. MyUserControl 的实例放到表单上,然后在属性编辑器窗口中,找到DataGridView 属性,展开并编辑Columns 并保存表单。

    这些列现在已序列化。给你。

    注意:自定义UITypeEditor是在this post的基础上做了一些改动。

    结果如下:

    private void InitializeComponent()
    {
        ...
        ...
    
        this.Column1 = new System.Windows.Forms.DataGridViewTextBoxColumn();
        this.Column2 = new System.Windows.Forms.DataGridViewTextBoxColumn();
        ((System.ComponentModel.ISupportInitialize)(this.myUserControl1.DataGridView)).BeginInit();
        this.SuspendLayout();
        // 
        // myUserControl1
        // 
        // 
        // 
        // 
        this.myUserControl1.DataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
        this.myUserControl1.DataGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
        this.Column1,
        this.Column2});
    
        ...
        ...
    
        // 
        // Column1
        // 
        this.Column1.HeaderText = "Column1";
        this.Column1.MinimumWidth = 6;
        this.Column1.Name = "Column1";
        this.Column1.Width = 125;
        // 
        // Column2
        // 
        this.Column2.HeaderText = "Column2";
        this.Column2.MinimumWidth = 6;
        this.Column2.Name = "Column2";
        this.Column2.Width = 125;
        
        ...
        ...
    
        ((System.ComponentModel.ISupportInitialize)(this.myUserControl1.DataGridView)).EndInit();
        this.ResumeLayout(false);
    
    }
    
    ...
    
    private System.Windows.Forms.DataGridViewTextBoxColumn Column1;
    private System.Windows.Forms.DataGridViewTextBoxColumn Column2;
    
    ...
    

    【讨论】:

    • 根据我的测试,我删除了保留在那里的不必要的代码部分。 (不需要自定义 ColumnCollection 和 CreateColumnCollectionDialog 覆盖。)
    • 现在它可能是最优雅的解决方案了??
    • 感谢您的回复以及您为我付出的时间。就我而言,当我添加一列并将其保存为 app 和 visualstudio 时,它不起作用。
    • 嗯,该解决方案在 VS 2019 - .NET 4.8 中进行了测试。我建议您从一个干净的项目开始,并严格按照步骤操作。让它工作后,您可以将其修改为您想要控制的任何内容。
    • 我在步骤 3 中混淆了组件类和用户控件。它工作正常。谢谢
    猜你喜欢
    • 2011-04-12
    • 2010-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-09
    • 2013-04-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多