C#中带参数的“UserControl”构造函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1784303/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
'UserControl' constructor with parameters in C#
提问by JustLooking
Call me crazy, but I'm the type of guy that likes constructors with parameters (if needed), as opposed to a constructor with no parameters followed by setting properties. My thought process: if the properties are required to actually construct the object, they should go in the constructor. I get two advantages:
叫我疯了,但我喜欢带参数的构造函数(如果需要),而不是没有参数然后设置属性的构造函数。我的思考过程:如果需要属性来实际构造对象,它们应该进入构造函数。我有两个优点:
- I know that when an object is constructed (without error/exception), my object is good.
- It helps avoid forgetting to set a certain property.
- 我知道当一个对象被构建时(没有错误/异常),我的对象是好的。
- 它有助于避免忘记设置某个属性。
This mindset is starting to hurt me in regards to form/usercontrol development. Imagine this UserControl
:
在表单/用户控件开发方面,这种心态开始伤害我。想象一下UserControl
:
public partial class MyUserControl : UserControl
{
public MyUserControl(int parm1, string parm2)
{
// We'll do something with the parms, I promise
InitializeComponent();
}
}
At designtime, if I drop this UserControl
on a form, I get an Exception
:
在设计时,如果我把它UserControl
放在一个表单上,我会得到一个Exception
:
Failed to create component 'MyUserControl' ...
System.MissingMethodException - No parameterless constructor defined for this object.
未能创建组件“MyUserControl”...
System.MissingMethodException - 没有为此对象定义无参数构造函数。
It seems like, to me, the only way around that was to add the default constructor (unless someone else knows a way).
对我来说,似乎唯一的方法是添加默认构造函数(除非其他人知道方法)。
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
}
public MyUserControl(int parm1, string parm2)
{
// We'll do something with the parms, I promise
InitializeComponent();
}
}
The whole point of not including the parameterless constructor was to avoid using it. And I can't even use the DesignMode
property to do something like:
不包括无参数构造函数的全部意义在于避免使用它。我什DesignMode
至不能使用该属性来执行以下操作:
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
if (this.DesignMode)
{
InitializeComponent();
return;
}
throw new Exception("Use constructor with parameters");
}
}
This doesn't work either:
这也不起作用:
if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
Fine, moving along ...
好吧,继续……
I have my parameterless constructor, I can drop it on the form, and the form's InitializeComponent
will look like this:
我有我的无参数构造函数,我可以把它放在表单上,表单InitializeComponent
看起来像这样:
private void InitializeComponent()
{
this.myControl1 = new MyControl();
// blah, blah
}
And trust me, because I did it (yes, ignoring the comments Visual Studio generated), I tried messing around and I passed parameters to InitializeComponent
so that I could pass them to the constructor of MyControl
.
相信我,因为我做到了(是的,忽略了 Visual Studio 生成的注释),我尝试搞砸了,我将参数InitializeComponent
传递给MyControl
.
Which leads me to this:
这让我想到了这个:
public MyForm()
{
InitializeComponent(); // Constructed once with no parameters
// Constructed a second time, what I really want
this.myControl1 = new MyControl(anInt, aString);
}
For me to use a UserControl
with parameters to the constructor, I have to add a second constructor that I don't need? And instantiate the control twice?
对于我使用UserControl
带参数的构造函数,我必须添加第二个不需要的构造函数?并将控件实例化两次?
I feel like I must be doing something wrong. Thoughts? Opinions? Assurance (hopefully)?
我觉得我一定是做错了什么。想法?意见?保证(希望)?
采纳答案by Greg D
Design decisions made regarding the way Windows Forms works more or less preclude parameterized .ctors for windows forms components. You can use them, but when you do you're stepping outside the generally approved mechanisms. Rather, Windows Forms prefers initialization of values via properties. This is a valid design technique, if not widely used.
关于 Windows 窗体工作方式的设计决策或多或少排除了 Windows 窗体组件的参数化 .ctors。您可以使用它们,但是当您使用它们时,您就超出了普遍认可的机制。相反,Windows 窗体更喜欢通过属性初始化值。如果没有广泛使用,这是一种有效的设计技术。
This has some benefits, though.
不过,这有一些好处。
- Ease of use for clients. Client code doesn't need to track down a bunch of data, it can immediately create something and just see it with sensible (if uninteresting) results.
- Ease of use for the designer. Designer code is clearer and easier to parse in general.
- Discourages unusual data dependencies within a single component. (Though even microsoft blew this one with the
SplitContainer
)
- 方便客户使用。客户端代码不需要追踪一堆数据,它可以立即创建一些东西,然后看到它带有合理(如果无趣)的结果。
- 便于设计师使用。总体而言,设计器代码更清晰且更易于解析。
- 阻止单个组件内异常的数据依赖性。(尽管即使是微软也用 炸毁了这个
SplitContainer
)
There's a lot of support in forms for working properly with the designer in this technique also. Things like DefaultValueAttribute
, DesignerSerializationVisibilityAttribute
, and BrowsableAttribute
give you the opportunity to provide a rich client experience with minimal effort.
在表单中也有很多支持与设计师在这种技术中正常工作。诸如DefaultValueAttribute
、DesignerSerializationVisibilityAttribute
和之类的东西BrowsableAttribute
让您有机会以最少的努力提供丰富的客户体验。
(This isn't the only compromise that was made for client experience in windows forms. Abstract base class components can get hairy too.)
(这并不是在 Windows 窗体中为客户端体验所做的唯一妥协。抽象基类组件也可能变得很麻烦。)
I'd suggest sticking with a parameterless constructor and working within the windows forms design principles. If there are real preconditions that your UserControl
must enforce, encapsulate them in another class and then assign an instance of that class to your control via a property. This will give a bit better separation of concern as well.
我建议坚持使用无参数构造函数并在 Windows 窗体设计原则内工作。如果确实存在UserControl
必须强制执行的先决条件,请将它们封装在另一个类中,然后通过属性将该类的实例分配给您的控件。这也将提供更好的关注点分离。
回答by Dan Bystr?m
Provide a parameterless constructor for the designer and make it private - if you really must do it this way... :-)
为设计器提供一个无参数的构造函数并将其设为私有——如果你真的必须这样做...... :-)
EDIT: Well of course this won't work for UserControls. I obviously wasn't thinking clearly. The designer need to execute the code in InitializeComponent() and it's can't work if the constructor is private. Sorry about that. It doeswork for forms, however.
编辑:当然这不适用于 UserControls。我显然没有想清楚。设计者需要执行 InitializeComponent() 中的代码,如果构造函数是私有的,它就无法工作。对于那个很抱歉。但是,它确实适用于表单。
回答by Reed Copsey
This is unfortunately a design issue that will occur frequently, not just in the control space.
不幸的是,这是一个经常发生的设计问题,而不仅仅是在控制空间中。
There are often situations where you need to have a parameterless constructor, even though a parameterless constructor is not ideal. For example, many value types, IMO, would be better off without parameterless constructors, but it's impossible to create one that works that way.
经常存在需要无参数构造函数的情况,即使无参数构造函数并不理想。例如,许多值类型,IMO,如果没有无参数构造函数会更好,但不可能创建一个那样工作的构造函数。
In these situations, you have to just design the control/component in the best manner possible. Using reasonable (and preferably the most common) default parameters can help dramatically, since you can at least (hopefully) initialize the component with a good value.
在这些情况下,您必须尽可能以最佳方式设计控件/组件。使用合理的(最好是最常见的)默认参数会很有帮助,因为您至少可以(希望)用一个好的值初始化组件。
Also, try to design the component in a way that you can change these properties after the component is generated. With Windows Forms components, this is typically fine, since you can pretty much do anything until load time safely.
此外,尝试以一种可以在生成组件后更改这些属性的方式来设计组件。对于 Windows 窗体组件,这通常很好,因为在安全加载之前您几乎可以做任何事情。
Again, I agree - this isn't ideal, but it's just something we have to live with and work around.
再次,我同意 - 这并不理想,但这只是我们必须忍受和解决的事情。
回答by Bob Nadler
Just do this:
只需这样做:
public partial class MyUserControl : UserControl
{
public MyUserControl() : this(-1, string.Empty)
{
}
public MyUserControl(int parm1, string parm2)
{
// We'll do something with the parms, I promise
if (parm1 == -1) { ... }
InitializeComponent();
}
}
Then the 'real' constructor can act accordingly.
然后“真正的”构造函数可以相应地采取行动。
回答by Fredrik M?rk
Well, in short, the designer is the kind of guy that likes parameter-less constructors. So, to the best of my knowledge, if you really want to use parameter based constructors you are probably stuck with working around it one way or the other.
嗯,简而言之,设计师是那种喜欢无参数构造函数的人。因此,据我所知,如果您真的想使用基于参数的构造函数,您可能会以一种或另一种方式解决它。
回答by Antony Koch
I would recommend
我会推荐
public partial class MyUserControl : UserControl
{
private int _parm1;
private string _parm2;
private MyUserControl()
{
InitializeComponent();
}
public MyUserControl(int parm1, string parm2) : this()
{
_parm1 = parm1;
_parm2 = parm2;
}
}
As this way the base constructor is always called first and any references to components are valid.
通过这种方式,总是首先调用基本构造函数,并且对组件的任何引用都是有效的。
You could then overload the public ctor if need be, ensuring the control is always instantiated with the correct values.
然后,如果需要,您可以重载公共 ctor,确保始终使用正确的值实例化控件。
Either way, you ensure that the parameterless ctor is never called.
无论哪种方式,您都可以确保永远不会调用无参数 ctor。
I haven't tested this so if it falls over I apologise!
我还没有测试过这个,所以如果它摔倒了,我道歉!
回答by Kevin Kibler
There are two competing paradigms for designing classes:
设计类有两种相互竞争的范式:
- Use parameterless constructors and set a bunch of properties afterwards
- Use parameterized constructors to set properties in the constructor
- 使用无参数构造函数,然后设置一堆属性
- 使用参数化构造函数在构造函数中设置属性
The Visual Studio Windows Forms Designerforces you to provide a parameterless constuctor on controls in order to work properly. Actually, it only requires a parameterless constructor in order to instantiate controls, but not to design them (the designer will actually parse the InitializeComponent method while designing a control). This means that you can use the designer to design a form or user control without a parameterless constructor, but you cannot design another control to use that control because the designer will fail to instantiate it.
在Visual Studio中的Windows窗体设计器迫使你工作提供控件参数的constuctor才能正常。实际上,它只需要一个无参数的构造函数来实例化控件,而不是设计它们(设计者在设计控件时实际上会解析 InitializeComponent 方法)。这意味着您可以使用设计器在没有无参数构造函数的情况下设计窗体或用户控件,但不能设计另一个控件来使用该控件,因为设计器将无法实例化它。
If you don't intend to programmatically instantiate your controls (i.e. build your UI "by hand"), then don't worry about creating parameterized constructors, since they won't be used. Even if you are going to programmatically instantiate your controls, you may want to provide a parameterless constructor so they can still be used in the designer if need be.
如果您不打算以编程方式实例化您的控件(即“手动”构建您的 UI),那么不要担心创建参数化构造函数,因为它们不会被使用。即使您打算以编程方式实例化您的控件,您也可能希望提供一个无参数的构造函数,以便在需要时仍然可以在设计器中使用它们。
Regardless of which paradigm you use, it is also generally a good idea to put lengthy initialization code in the OnLoad()
method, especially since the DesignMode
property will work at load time, but not work in the constructor.
无论您使用哪种范式,在OnLoad()
方法中放置冗长的初始化代码通常也是一个好主意,特别是因为该DesignMode
属性将在加载时起作用,但在构造函数中不起作用。
回答by Hermilton
It's quite a while since the question was asked, but maybe my approach is helpful to somebody.
问这个问题已经有一段时间了,但也许我的方法对某人有帮助。
I personally also prefer to use parameterized Constructors to avoid forgetting to set a certain property.
我个人也更喜欢使用参数化构造函数来避免忘记设置某个属性。
So instead of using the actual Constructor I simply define a public void PostConstructorwhere all things are put you would normally put in the Constructor. So the Actual Constructor of the UserControl always contains only InitializeComponent(). This way you don't have to adjust your favourite programming paradigm to VisualStudios needs to run the Designer properly. For this programming schema to work it has to be followed from the very bottom.
因此,我没有使用实际的构造函数,而是简单地定义了一个public void PostConstructor,其中所有的东西都放在你通常会放在构造函数中的地方。因此 UserControl 的实际构造函数始终只包含InitializeComponent()。这样您就不必根据 VisualStudios 正确运行设计器的需要调整您最喜欢的编程范式。为了让这个编程模式起作用,它必须从最底层开始。
In practice this PostConstructionalizmwould look somewhat like this: Let's start with a Control at the bottom of your UserControl call hierarchy.
在实践中,这个PostConstructionalizm看起来有点像这样:让我们从 UserControl 调用层次结构底部的 Control 开始。
public partial class ChildControl : UserControl
{
public ChildControl()
{
InitializeComponent();
}
public void PostConstructor(YourParameters[])
{
//setting parameters/fillingdata into form
}
}
So a UserControl containing the ChildControl would look something like that:
所以包含 ChildControl 的 UserControl 看起来像这样:
public partial class FatherControl : UserControl
{
public FatherControl()
{
InitializeComponent();
}
public void PostConstructor(YourParameters[])
{
ChildControl.PostConstructor(YourParameters[])
//setting parameters/fillingdata into form
}
}
And finally a Form calling one of the User Control simply puts the PostConstructor after InitializeComponent.
最后,调用用户控件之一的 Form 只是将 PostConstructor 放在InitializeComponent之后。
public partial class UI : Form
{
public UI(yourParameters[])
{
InitializeComponent();
FatherControl.PostConstructor(yourParameters[]);
}
}
回答by Eric Chow
I have a way to work around it.
我有办法解决它。
- Create a control A on the form with the parameterless constructor.
- Create a control B with parameterized constructor in the form contstructor.
- Copy position and size from A to B.
- Make A invisible.
- Add B to A's parent.
- 使用无参数构造函数在窗体上创建一个控件 A。
- 在表单构造函数中创建一个带有参数化构造函数的控件 B。
- 将位置和大小从 A 复制到 B。
- 使 A 不可见。
- 将 B 添加到 A 的父级。
Hope this will help. I just encountered the same question and tried and tested this method.
希望这会有所帮助。我刚刚遇到了同样的问题,并尝试并测试了这种方法。
Code for demonstrate:
演示代码:
public Form1()
{
InitializeComponent();
var holder = PositionHolderAlgorithmComboBox;
holder.Visible = false;
fixedKAlgorithmComboBox = new MiCluster.UI.Controls.AlgorithmComboBox(c => c.CanFixK);
fixedKAlgorithmComboBox.Name = "fixedKAlgorithmComboBox";
fixedKAlgorithmComboBox.Location = holder.Location;
fixedKAlgorithmComboBox.Size = new System.Drawing.Size(holder.Width, holder.Height);
holder.Parent.Controls.Add(fixedKAlgorithmComboBox);
}
holder is Control A, fixedKAlgorithmComboBox is Control B.
持有人是控制A,fixedKAlgorithmComboBox是控制B。
An even better and complete solution would be to use reflect to copy the properties one by one from A to B. For the time being, I am busy and I am not doing this. Maybe in the future I will come back with the code. But it is not that hard and I believe you can do it yourself.
一个更好更完整的解决方案是使用reflect将属性从A一个一个地复制到B。暂时我很忙,我没有这样做。也许将来我会带着代码回来。但这并不难,我相信你可以自己做。
回答by mikmaksi
I had a similar problem trying to pass an object created in the main Windows Form to a custom UserControl form. What worked for me was adding a property with a default value to the UserControl.Designer.csand updating it after the InitializeComponent() call in the main form. Having a default value prevents WinForms designer from throwing an "Object reference not set to an instance of an object" error.
我在尝试将在主 Windows 窗体中创建的对象传递给自定义 UserControl 窗体时遇到了类似的问题。对我有用的是向UserControl.Designer.cs添加一个具有默认值的属性,并在主窗体中的 InitializeComponent() 调用之后更新它。使用默认值可防止 WinForms 设计器抛出“未将对象引用设置为对象的实例”错误。
Example:
例子:
// MainForm.cs
public partial class MainForm : Form
public MainForm()
{
/* code for parsing configuration parameters which producs in <myObj> myConfig */
InitializeComponent();
myUserControl1.config = myConfig; // set the config property to myConfig object
}
//myUserControl.Designer.cs
partial class myUserControl
{
/// <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);
}
// define the public property to hold the config and give it a default value
private myObj _config = new myObj(param1, param2, ...);
public myObj config
{
get
{
return _config ;
}
set
{
_config = value;
}
}
#region Component Designer generated code
...
}
Hope this helps!
希望这可以帮助!