Designer 不序列化 UserControl 的 DataGridView 属性 的列

Designer doesn't serialzie Columns of a DataGridView property of a UserControl

我正在尝试创建一个包含标签、工具条和 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
...

求助,我想明白我哪里错了?

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

  1. 创建自定义 MyDataGridView 派生自 DataGridView:

     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 的实例拖放到您的表单上,然后在 属性 编辑器 window 中找到 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;

...