How to add a custom control to the toolbox? - c#

I've created a custom control, based on the Picturebox:
public class Timebar : System.Windows.Forms.PictureBox
This works correctly if I create the control manually/set all values etc. etc, at the Form's initialization method.
Now I also found this, at the top of the Toolbox: http://i.imgur.com/4KUc0.png
When I try to insert it via msvc, I get an error however.
Failed to create component 'Timebar'. The error message follows:
'System.MissingMethodException: Constructor on type 'SC.Timebar' not found.
This isn't exactly a huge problem with my component Timebar (as I will add that component manually), but it is with the custom Button class I want to make (something more fancy then the default).
There IS a constructor in the class:
public Timebar(Data refr)
{
this._refr = refr;
}
How can I fix the above error?
Thanks,
~ Tgys

Controls used in the designer must have a parameterless constructor. The designer needs to create one of your controls to display and allow you to manipulate it, but it has no clue as to how it should call a constructor that requires parameters.
So, what I would do is create a parameterless constructor which chains the other constructor using a default value, i.e.,
class Foo
{
public Foo() : this(SomeType.Value) { }
public Foo(SomeType whatever) : { /* do stuff /* }
}

Related

UserControl with generic control - broken in designer

I have a WinForm-UserControl with a generic type for a control. To create the instance, I changed the Designer code:
public class TimeBarForm<T> : where T : TimeBarPanel
{
protected void InitializeComponent()
{
// ...
this.m_timeBarPanel = (T)Activator.CreateInstance(typeof(T));
// ...
}
}
This works fine at compile time but on design time it's broken. On the TimeBarForm:
Failed to parse method 'InitializeComponent'. The parser reported the following error
'Type parameters are not suppported Parameter name: typeSymbol'.
Please look in the Task List for potential errors.
The derived classes just show the default designer for an empty user control.
I also tried to pass the type in the constructor but VS complains that I should not touch autogenerated code (It dosn't like the if-conditions). I want a generic UserControl where I can decide about the specialization of an abstract class/control in a derived type and I should still be able to use the designer in the base class. I'm open to other suggestions to solve this as this might not be the best solution. I'm not very used to UserControl-design.
VS 2015/ .Net 4.6
I've done a somewhat dirty workaround but I can use the designer for the base and derived classes. I removed the generic and replaced the Activator-class with a call to the constructor. When I'm done with designing the base class I coment this line. The derived classes call the constructor to pass the instance:
public TimeBarForm(TimeBarPanel timeBarPanel)
{
this.m_timeBarPanel = timeBarPanel;
InitializeComponent();
}
To make the designer for the derived classes happy, a second constructor provides a default instance:
public TimeBarForm()
{
this.m_timeBarPanel = new TimeBarPanel();
InitializeComponent();
}
Not pretty but I can live with it.

C# Winforms Designer calling base property instead of 'new' one?

I have a class that inherits from another class, who has a non-virtual property ("Controls").
Since I can't overwrite this property, Im using the 'new' keyword associated with my property.
At runtime, this property is called as I want it to, in the correct context.
When I open my form from the designer, the designer calls the base.Controls instead of my 'new' control.
Am I missing something, or is this just incorrect behavior in the winforms designer?
Edit, added the code in question for more explanation. I have the following class:
public partial class BauerGroupBox : ComponentFactory.Krypton.Toolkit.KryptonGroupBox
{
public BauerGroupBox()
: base()
{
}
public new Control.ControlCollection Controls
{
get
{
MessageBox.Show("GOT THERE");
return this.Panel.Controls;
}
}
}
When I get to the following code in my intializecomponent:
BauerGroupBox thisBox = new BauerGroupBox()
thisBox.Controls.Add(something)
When I add a new 'BauerGroupBox' to my code, it works fine. However, when I open my code in the designer (even while using the debugging the devenv), the messagebox is NOT shown, and the breakpoint is NOT hit.
When I run my app, the breakpoint is hit.
You're missing something - what you're describing is correct behaviour.
The workaround is to re-populate your new Controls property right after the call to InitializeComponent(). Like so:
public MyForm() {
InitializeComponent();
this.Controls.AddRange( base.Controls );
}
However, why are you trying to "override" the Controls property? What new, non-standard, behaviour are you after? I believe there is a better alternative.
You misunderstand how the new keyword works. New doesn't override the property, it hides it. If you reference the object as it's base element, it will still call the base property, not your new one. The only way to use the new one is to reference it as the new one. ie.
public class A {
public A1 {get;set;}
}
public class B : A {
public new A1 {get;set;}
}
B b = new B();
A a = b;
a.A1; // references A.A1
b.A1; // references B.A1
I think I understand your situation, so let me explain what the designer is doing:
First, at runtime, you are effectively running an instance of your BauerGroupBox control. (That said, it's also all likely that you are accessing the Controls property through a reference of this derived type, namely BauerGroupBox, and as #Mystere Man correctly argues, the member BauerGroupBox.Controls hides the inherited member (wherever it is last defined) -- it does not override it.
Bur the issue in question is that at design-time, in the designer of the BauerGroupBox control, you are NOT "running" an instance of BauerGroupBox, instead you are designing a prototype based on ComponentFactory.Krypton.Toolkit.KryptonGroupBox and that is effectively the type of the control you are "running".
I repeat, the designer of BauerGroupBox does not have an instance of BauerGroupBox running, but an instance of ComponentFactory.Krypton.Toolkit.KryptonGroupBox. No BauerGroupBox exists in the designer, because, well.. you are designing it!!!
NOW, to add a bit more confusion to that (none really, it's all very simple if you think a bit about it,) you will see that if you go to any other designer of any other control, say a form, and then you drag and drop an instance of your BauerGroupBox, and add some controls to it, you will your message box, and yes, in that case, just like in the "runtime" case, it means that you are effectively hosting a BauerGroupBox... but in this case, you are not designing BauerGroupBox.
As other #Dai mentioned, if what you're trying to do is to prevent people from adding controls to it, then you should follow other design plans: for example, override the
protected virtual Control.ControlCollection CreateControlsInstance();
method.

Design-Time Errors in the Windows Forms Designer

I have this classes on the same namespace:
public partial class BaseForm : Form
{
bool isNew = false;
public BaseForm() {}
public BaseForm(bool isNew)
{
InitializeComponent();
this.isNew = isNew;
}
.
.
.
}
public partial class BitSetForm : BaseForm
{
public BitSetForm(bool isNew) : base(isNew)
{
InitializeComponent();
}
new private void InitializeComponent()
{
.
.
.
}
}
1) And I got this warning: Could not find type "..BaseForm," Please make sure that the assembly that contains this type is referenced. If this type is a part of your development project, make sure that the project has been successfully built using the setting for your current platform or Any CPU.
2) Design-Time Errors in the Windows Forms Designer appears and hiding the design pane of the "BitSetForm" win-form.
What does this mean? What can I do to make the design pane of the "BitSetForm" win-form display again?
You need to add a parameterless constructor to your BaseForm.
It can even be private; it just needs to exist.
Without one, the designer is unable to create an instance of the BaseForm to show in the design surface.
Remember to call InitializeComponent in the constructor.
Well a couple things...
You need to build your application before the designer can instantiate your base class. This can be very difficult if your subclass form has a bunch of errors.
The designer can only instantiate a class that has a default parameterless constructor. So that means your base class's BaseForm(bool isNew) will never be called by the designer. Which means InitializeComponent will not either. You should move InitializeComponent to the parameterless constructor and have the second constructor call the first.
InitializeComponent is private by default. You should not change its visibility to protected and since it's private, no new modifier is needed.
InitializeComponent should never be chained that way to the base class. It should only be called by the constructor.
Given all those issues, I would highly recommend either giving up on Windows Forms inheritance or at least moving your base class into a separate assembly. I've tried it many times and it's more trouble than it's worth.
The key thing to remember is that when you're viewing a form in the designer, the designer is not creating an instance of the form you see - it's creating an instance of the base class. At runtime that is obviously not the case. So it's very common to see different runtime/design time behavior.
As mentioned by #SLaks, you need the InitializeComponent in the constructor of your class. I would actually have it in the no-parameter instance. Then, in the constructor of you boolean, i would change to
public partial class BaseForm : Form
{
bool isNew = false;
public BaseForm()
{
InitializeComponent();
}
public BaseForm(bool isNew) : this()
{
this.isNew = isNew;
}
}
So if you had other stuff you wanted performed within your BaseForm definition regardless of a parameerized startup, that too would be called. This way, the InitializeComponent is triggeed in EITHER case.

'UserControl' constructor with parameters in C#

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:
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:
Failed to create component 'MyUserControl' ...
System.MissingMethodException - No parameterless constructor defined for this object.
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:
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:
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.
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?
I feel like I must be doing something wrong. Thoughts? Opinions? Assurance (hopefully)?
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.
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)
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.
(This isn't the only compromise that was made for client experience in windows forms. Abstract base class components can get hairy too.)
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.
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 Designer forces 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.
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.
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.
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.
Either way, you ensure that the parameterless ctor is never called.
I haven't tested this so if it falls over I apologise!
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.
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.
Again, I agree - this isn't ideal, but it's just something we have to live with and work around.
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.
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.
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 does work for forms, however.
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 PostConstructor where 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.
In practice this PostConstructionalizm would look somewhat like this:
Let's start with a Control at the bottom of your UserControl call hierarchy.
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:
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.
public partial class UI : Form
{
public UI(yourParameters[])
{
InitializeComponent();
FatherControl.PostConstructor(yourParameters[]);
}
}
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.
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.
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.
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.cs and 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.
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!

Fix embedded resources for a generic UserControl

During a refactoring, I added a generic type parameter to MyControl, a class derived from UserControl. So my class is now MyControl<T>.
Now I get an error at runtime stating that the embedded resource file MyControl`1.resources cannot be found. A quick look with .NET Reflector shows that the resource file is actually called MyControl.resources, without the `1.
At the start of the MyControl<T>.InitializeComponent method there is this line which is probably the one causing problems:
System.ComponentModel.ComponentResourceManager resources =
new System.ComponentModel.ComponentResourceManager(
typeof(MyControl<>));
How do I force the ComponentResourceManager to use the embedded resource file MyControl.resources? Other ways to resolve this issue are also welcome.
Turns out you can override the resource filename to load by inheriting from ComponentResourceManager like this:
using System;
using System.ComponentModel;
internal class CustomComponentResourceManager : ComponentResourceManager
{
public CustomComponentResourceManager(Type type, string resourceName)
: base(type)
{
this.BaseNameField = resourceName;
}
}
Now I can make sure that the resource manager loads MyControl.resources like this:
System.ComponentModel.ComponentResourceManager resources =
new CustomComponentResourceManager(typeof(MyControl<>), "MyControl");
This seems to work.
edit: the above line is overwritten if you use the designer, because it is in the
generated code region. I avoid the designer and make use of version control tools to revert any unwanted changes, but the solution is not ideal.
In addition to Wim's technique, you can also declare a non-generic base control that has the same name as your generic class, and have your generic control/form derive from that non-generic base class.
This way you can trick both the designer and the compiler into using the resource file from your generic class, and you get permanent designer support once the base class is setup without having to fiddle in the .designer file everytime you rebuild :
// Empty stub class, must be in a different file (added as a new class, not UserControl
// or Form template)
public class MyControl : UserControl
{
}
// Generic class
public class MyControl<T> : MyControl
{
// ...
}
The only requirements are to have exactly the same name for your generic class and its base class, and that the base class must be in another class file, otherwise the designer complains about not finding one of the two classes.
PS. I tested this with forms, but it should work the same with controls.
On my Visual Studio 2008 I have this error:
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MyControl));
Using the generic type 'WindowsFormsApplication1.UserControl1' requires '1' type arguments.
Notice that in my case code was generated without parentheses, <>, after the class name.
It is becoming interesting, see ImageList autogenerates non-compiling code in a Generic User Control.
What they said:
Posted by Microsoft on 7/6/2005 at 2:49 PM
This is an interesting bug. You've hit upon a generic scneario that we do not support in the Windows Forms designer. We will not be able to add support for this in the Whidbey (my note: Visual Studio 2008?) release. We will consider this for a future version. As a workaround, you can use the designer to create a none generic UserControl with a public Type property and then create a generic class that inherits from it and passes T into the base classes Type property.
I suppose this control cannot be designed in the Visual Studio forms designer either.
The simplest and easiest workaround is to make a dummy class for the autogenerated typeof(). You do not need to inherit from it or even expose it to the outside:
// Non-generic name so that autogenerated resource loading code is happy
internal sealed class GridEditorForm
{
}
(In my experience, the time required getting the designer to work around generics was not worth the ideal coolness generics can provide. I won't be using generic windows forms or controls again.)

Categories