Reputation: 8132
I added some screenshots and steps to reproduce below.
My data model has a base class, let's call it CommonThing
which has lots of properties. Then there are several specialized versions of this class with additional properties. I now want to create a UI to input data into this model.
I created a UserControl
which contains controls for all the common properties like this:
internal partial class CommonThingControl : UserControl {
public CommonThingControl() {
InitializeComponent();
}
// Controller code
}
This also adds a CommonThingControl.Designer.cs
which is populated by the GUI designer.
I now created a SpecialFooThingControl
as a UserControl
and changed the class header to read:
internal partial class SpecialFooThingControl : CommonThingControl {
// implementation
}
When I now open the SpecialFooThingControl
in the GUI designer, I see the controls of the CommonThingControl
but they are all locked. I however have a TableLayoutPanel
in the CommonThingControl
I want to add stuff to, but I cannot change anything, and when I try to drag a control into the TableLayoutPanel
the mouse cursor becomes a "No parking" sign and VS does not let me. This even happens when I set the accessor of the TableLayoutPanel
to public
.
I can move a control into the TableLayoutPanel
via the document outline, but when I then rebuild the project, it disappears from the UI.
Is what I am trying to achieve not possible with the UI designer and do I have to set this up by hand or is there some additional step I forgot?
Here is what I did:
First, created a User Control, this is straightforward. I created a table layout panel which I set to Protected
because I want to add to it.
This is the code for FooControl.cs
:
namespace GuiTest {
public partial class FooControl : UserControl {
public FooControl() {
InitializeComponent();
}
}
}
And FooControl.Designer.cs
:
namespace GuiTest {
partial class FooControl {
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.label1 = new System.Windows.Forms.Label();
this.textBox1 = new System.Windows.Forms.TextBox();
this.tableLayoutPanel1.SuspendLayout();
this.SuspendLayout();
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 2;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.Controls.Add(this.label1, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.textBox1, 1, 0);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 1;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.Size = new System.Drawing.Size(360, 28);
this.tableLayoutPanel1.TabIndex = 0;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(3, 7);
this.label1.Margin = new System.Windows.Forms.Padding(3, 7, 3, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(25, 13);
this.label1.TabIndex = 0;
this.label1.Text = "Foo";
//
// textBox1
//
this.textBox1.Dock = System.Windows.Forms.DockStyle.Top;
this.textBox1.Location = new System.Drawing.Point(34, 3);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(323, 20);
this.textBox1.TabIndex = 1;
//
// FooControl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.tableLayoutPanel1);
this.Name = "FooControl";
this.Size = new System.Drawing.Size(360, 28);
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
this.ResumeLayout(false);
}
#endregion
protected System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox textBox1;
}
}
Now I changed the extend from UserControl
to FooControl
in BarControl.cs
:
namespace GuiTest {
public partial class BarControl : FooControl {
public BarControl() {
InitializeComponent();
}
}
}
BarControl.Designer.cs
:
namespace GuiTest {
partial class BarControl {
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
}
#endregion
}
}
Upvotes: 2
Views: 1864
Reputation: 34489
The reason that the controls in CommonThingControl
are locked is because the sub-class SpecialFooThingControl
doesn't have access to them (they are privately scoped).
What you can do however in the designer for CommonThingControl
is change the modifiers property on them, which will allow you to consume/modify them in your sub-class. You need to do this on each individual control, and can simply change the dropdown in the Properties window. You can probably change them in the commonthingcontrol.designer.cs
file however I would also be wary on the basis that this file is auto-generated and changes can easily be over-written if you're not careful.
I'd recommend using something like Protected
to ensure they're visible to the sub-controls but prevent them being abused outside of the inheritance chain.
EDIT
So further looking into this reveals that this is a limitation of the TableLayoutPanel
. Taken from https://msdn.microsoft.com/en-us/library/ms171689.aspx:
Avoid Visual Inheritance The TableLayoutPanel control does not support visual inheritance in the Windows Forms Designer. A TableLayoutPanel control in a derived class appears as "locked" at design time.
Upvotes: 1
Reputation: 458
Due to controls accessibility, you cannot update them.
To do so, go into your CommonThingControl.Designer.cs, change for exemple private Button MyButton1
to protected Button MyButton1
Upvotes: 0