我创建了一个用户控件,我需要在读取属性Controls时返回一个由我指定的ControlCollection而不是基本属性Control.Controls
我这样做了,如果我读取CustomGroupBox.Controls它有效但是如果一个方法将控件作为参数(它接收任何类型的控件,如CustomGroupBox,Button,Panel等),尝试读取它获得的Control.Controls基础ControlCollection。
让我用代码解释我的问题
CustomGroupBox.cs
public partial class CustomGroupBox : UserControl
{
Panel Panel1 = null;
Panel Panel2 = null;
bool UseBaseControls = true;
public CustomGroupBox()
{
InitializeComponent();
Panel1 = new Panel() { Name = "Panel1" };
Panel2 = new Panel() { Name = "Panel2" };
Controls.Add(Panel1);
Controls.Add(Panel2);
UseBaseControls = false;
}
public new ControlCollection Controls { get { return UseBaseControls ? base.Controls : Panel1.Controls; } }
}
Form1.cs的
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
CustomGroupBox Container = new CustomGroupBox();
Container.Controls.Add(new Button());
Container.Controls.Add(new Button());
Container.Controls.Add(new Button());
Container.Controls.Add(new Button());
Control Parameter = Container;
int i = Container.Controls.Count; // i=4
int j = Parameter.Controls.Count; // j=2
}
}
有谁知道我必须在CustomGroupBox.cs上更改,所以j = 4?
更新
我找不到解决方案,我试图实现像IContainerControl这样的interfaz,但它不起作用。
答案 0 :(得分:1)
嗯,这里的主要问题是UserControl.Controls属性不是虚拟的,因此不能在派生的CustomGroupBox
类中重写。换句话说,该物业的吸气剂没有vtable条目。
因此,任何将对象实例视为基类类型之一(UserControl
,Control
等)并调用Controls
属性的代码都将从基础获取结果类。
此处使用new
关键字可以让您有效地向Controls
类添加一个名为CustomGroupBox
的全新属性,但该新属性实际上与该属性不同在基类中具有相同名称。那么,调用新属性的getter的唯一方法是通过一个强类型为CustomGroupBox
的变量。
一种技巧是将Parameter
中的Form1_Load
变量“转发”到CustomGroupBox
,但在更复杂的情况下,这可能并不总是适合您。
您可以编写如下代码:
Control Parameter = Container;
int j = ((Parameter as CustomGroupBox)?.Controls ?? Parameter.Controls).Count;
此代码将在调用Control
属性getter之前尝试从CustomGroupBox
到Controls
的安全upcast,如果{{Controls
属性getter则返回到基类Parameter
属性getter 1}}实际上不是CustomGroupBox
。