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!
Related
I made a program that works just fine as-is, however i want to organize code better by moving some of my logic into other .cs files; upon moving some code i noticed that code reffering the "this" keyword for changing the applications width / height no longer function and ive had no luck trying to get a handle to "this", please help
int heightd = (int)this.Height;
Edit: To further clarify. My mainwindow.xaml.cs is where all my code was before.
I would use this.width to get my windows width.
Upon creating a different .cs file to hold related methods, it broke all of my "this" refferences.
I want for my NEW cs file to be able to get a handle on "this" from my main program. so i can call its width, height, etc
Re-edit: I understand that "this" is not going to function properly from my new class I just want to be able to create methods that use the same object that is accessed when "this" is refferenced.
So for example, Class2 can do WorkAround.height ; where WorkAround is a handle to whatever "this" is in class 1.
Soution: updated signature in new class to accept the main window:
public static void Marginnn(MainWindow aplication)
{
send "this" from main class during the call:
WindowsInterop.Marginnn(this);
Others have discussed partial classes, which can be problematic. For this answer, I assume by "move to another .cs file" you mean "move to another class," as your title indicates.
The this keyword is effectively a variable that refers to the instance that "owns" the current method. If the method is moved to another type, then the instance can no longer be the owner of the method. Instead, you need to pass a reference to the instance into the method instead. That will be a method parameter, which will have a name other than this.
Example; before:
class App
{
public void DoSomethingWithTheHeight()
{
int heightd = (int)this.Height;
//more code
}
public void CallDoSomethingWithTheHeight()
{
this.DoSomethingWithTheHeight();
}
}
Task: move DoSomethingWithTheHeight to a new static class:
class App
{
public void CallDoSomethingWithTheHeight()
{
NewClass.DoSomethingWithTheHeight(this);
}
}
static class NewClass
{
public static void DoSomethingWithTheHeight(App application)
{
int heightd = (int)application.Height;
//more code
}
}
Task: move DoSomethingWithTheHeight to a new non-static class:
class App
{
public void CallDoSomethingWithTheHeight()
{
NewClass instanceOfNewClass = new NewClass();
instanceOfNewClass.DoSomethingWithTheHeight(this);
}
}
class NewClass
{
public void DoSomethingWithTheHeight(App application)
{
int heightd = (int)application.Height;
//more code
}
}
There are other possibilities, but these examples should illustrate the basic principle.
If you only want to move part of your class to another file and still use this, you have to use a partial class. But I won't recommend this approach, your code clearly needs some refactoring.
C# keyword this refers to the current instance of the class it's being used in. It can be used for a few other things such as a modifier of the first parameter of an extension method, but we won't worry about that here. So, you may only use this from within the class that it's referring to and note that it may not be used with static classes, methods, fields, etc... since they have no instance associated with them.
If the code you're referring to is not implemented within a partial class, then it has to refer to the instance of the Window. Otherwise, it's impossible to tell what this is. Since we don't know how exactly you're structuring your program, it's hard to recommend a method of fetching the instance of the Window in question. If, for example, you would use the MVVM pattern, you wouldn't even need to interact with the instance of the UI from within the code. However, if you're working with a code-behind model, then your best bet is probably to create a partial class for that window. Like I said, it's hard to know what's right in your situation without knowing the entire scope of your environment.
There are lots of ways to tackle this and some are more hackish than others:
// In the code-behind of a window...
public static MyWindow Instance { get; private set; }
public MyWindow()
{
Initialize();
Instance = this;
}
// Somewhere else in your program...
var someValue = MyWindow.Instance.SomeControl.Value;
Note that the above code is just for demonstration purposes and not something I would recommend doing (it doesn't even account for null, but that's easy to fix). It's simply a demonstration showing that there are almost countless ways of tackling your problem. Ideally, if you're not going with MVVM, I would probably implement a window manager class that handles instances of all of your application windows.
I've searched everywhere on this and can't find anyone doing anything similar. I'm quite a newbie at C# having worked 15 years with a non-object orientated language, so I hope I'm not missing something simple.
I am trying to make a standard Winform which get's inherited, so that I don't need to repeat the code I use every time (one of the joys of .Net over what I've used for years is the ability to centralize things far more).
My problem comes that I want to implement the ability to either call the derived classes as 'single instance' or 'multiple instance' when launched from the MDI and after much much searching I've almost achieved this using 'generics'. But I've got stuck with how to know which class the current form is, to pass that to the generic class to close the form.
A simplified version of my code will help understand my problem. This is my generic class designed for launching and closing the form. It determines if the Instance for T already exists, depending on if you are launching a single or multiple instance it either shows that, or creates a new instance of the form. The MDI for is passed in the launch methods to allow me to attach the new form to that.
public class FormLaunch<T> where T : MyBaseForm, new()
{
public static T Instance;
public static void LaunchultipleInstnace(FRMMDI mdi)
{
Instance = new T();
Instance.MdiParent = mdi;
Instance.Show();
Instance.BringToFront();
}
public static void LaunchSingleInstance(FRMMDI mdi)
{
if (Instance == null) Instance = new T();
Instance.MdiParent = mdi;
Instance.Show();
Instance.BringToFront();
}
public static void CloseInstance()
{
Instance = null;
}
}
A 'Single Instance' version of the form is launched from the MDI using the following statement.
FormLaunch<MyDerivedClass>.LaunchSingleInstance(this);
The problem comes that I would like to handle the closing of the form once in my base form and not have to do it every time in the derived forms. But I can't work out how to do this.
public partial class MyBaseForm : Form
{
public MyBaseForm()
{
InitializeComponent();
}
private void MyBaseForm_FormClosed(object sender, FormClosedEventArgs e)
{
FormLaunch<this.GetType()>.CloseInstance();
}
}
But this.GetType() does not work. If I was just using this form directly rather than inheriting it I could just use
FormLaunch<MyBaseForm>.CloseInstance();
Or if I handled the FormClosed event in every derived class then I could just use
FormLaunch<MyDerivedClass>.CloseInstance();
But I really want to do this in a way that stops me forgetting to do this every time in the derived class... because I wrote this a few months ago and have already forgotten pretty much every time I've used it.
EDIT: My question is really, what do I pass in the place of T in
FormLaunch<T>.CloseInstance()
This needs to refer to the derived class and I can't seem to find that. this.GetType() refers to the correct glass but does not work.
If what you want is just to enuse the single instance of the Form is opened you can read the answer of Jon Skeet to this question
And just a pair of another points.
You mix different things: .NET generics and inheritance.
this.GetType() returns an instance of System.Type class, describing the current instance class (this),
Type parameter in GenericClass<TypeParameter> is just a name of the concrete class in using, or a type parameter name in the generic class definition: Generic<TParam>
you can't define generic Control or Form classes. The Designer is not capable to serialize them.
You can simply subscribe to FormClosed in LaunchSingleInstance() and remove handling of close event from form itself completely:
public static void LaunchSingleInstance(FRMMDI mdi)
{
if (Instance == null)
{
Instance = new T();
Instance.FormClosed += (s, e) => CloseInstance();
}
Instance.MdiParent = mdi;
Instance.Show();
Instance.BringToFront();
}
A more direct answer - it is possible using reflection:
typeof(FormLaunch<>).MakeGenericType(this.GetType())
.GetMethod("CloseInstance")
.Invoke(null, null);
I have a UserControl hierarchy that looks something like this:
public class BaseClass : UserControl
{
protected Label[] Labels;
public BaseClass(int num)
{
Labels = new Label[num];
for(int i=0; i<num; i++)
{
Labels[i] = new Label();
}
}
}
And in a different file:
public class DerivedClass : BaseClass
{
public DerivedClass() : base(2)
{
// Do stuff to the location, size, font, text of Labels
}
}
This structure is designed so that the BaseClass handles core logic and DerivedClass handles display logic. The number of Labels needs to be variable (different DerivedClasses will have different num values).
My problem is that I would like the designer view to show the UserControl as it would look after the display adjustments. There are several problems -- first, if BaseClass lacks a default constructor, then the DerivedClass's designer view just fails. Even if I add a default constructor, the designer view shows the layout of DerivedClass without the various display changes.
I'm not interested in using the designer view to change the Controls. I'm not opposed to it, but the fact that Labels are in an Array seems to prevent the designer view from being able to access them. I am simply interested in being able to see the effects of my display layout code in the DerivedClass.
There appears to be a limitation in the Windows Forms designer that prevents the currently designed class' own constructor from running - only the parent class(es) constructors are fired.
If I take your example:
public partial class BaseControl : UserControl
{
public BaseControl()
{
InitializeComponent();
}
protected Label[] Labels;
public BaseControl(int num) : base()
{
Labels = new Label[num];
for(int i=0; i<num; i++)
{
Labels[i] = new Label();
}
}
}
public class DerivedControl : BaseControl
{
public DerivedControl() : base(5)
{
Controls.Add(Labels[0]);
Labels[0].Text = "Hello";
Labels[0].Location = new System.Drawing.Point(10, 10);
}
}
Then, when I look in the designer for Derived Control, I see nothing. However, if I add the following control derived from DerivedControl:
public class GrandchildControl : DerivedControl
{
public GrandchildControl() : base() { }
}
And, after building my project, look at that in the designer (Visual Studio 2010), I see:
It appears to be a feature of the designer. According to this blog post on MSDN blogs (which is quite old)
Form1 must be built before you can add another Form, say Form2,
that visually inherits from it. This is because the designer for
Form2 has to instantiate Form1, not System.Windows.Forms.Form. This
also explains why if you open Form2 in the designer, attach a
debugger to Visual Studio and set a breakpoint in Form1's
InitializeComponent, the breakpoint does get hit.
There is a comment above InitializeComponent that warns you against modifying
it manually. This is because the designer needs to parse this code,
and it has some limitations as to what it can parse. It is generally
guaranteed to parse whatever it serialized in there, but not
arbitrary code that you may add.
If you are manually (through code) adding a control to the form in the constructor or in the Load
event handler, the control doesn't show up in the designer. This is
because the designer doesn't parse that - it only parses
InitializeComponent.
The only way I have ever got this to reliably work is to either move all of my code into a method that get's called by InitializeComponent (and occasionally, you have to remember to stick it back in when it get's "overwritten" by the designer) or to do as I've done above and create a GrandchildUserControl to fake the constructor call of the actual control I'm interested in.
FWIW I believe this is a consequence of 1) and 3) and is almost certainly a work-around of something that is by design.
Point 1) also raises a great investigative technique for these situations - you can actually launch another instance of Visual Studio and attach to the first instance of Visual Studio and debug the method calls running there. This has helped me troubleshoot several designer issues in the past.
As dash pointed out, the designer create an instance of the base class, then parses the InitializeComponent method and executes its instructions. This means that there is no simple way to have it execute the code in the derived classes' constructors (you should parse the constructor and execute its instructions).
You have to be careful that the solution of having the derived class' specific instructions grouped in a method which is called inside InitializeComponent works only if the method is generic enough to be defined in the base class, since the designer is working with an instance of this base class. This means that if the method is declared as virtual in the base class that will be the one that is executed, whilst if there is no such method in the base class the designer will crash.
You could do something along these lines. Define this method in the base class:
protected void CreateLabels(int num)
{
Labels = new Label[num];
for(int i=0; i<num; i++)
{
Labels[i] = new Label();
this.Controls.Add(Labels[i]);
}
}
Then you have to call it in the InitializeComponent of your derived control passing the proper value of num.
All of your settings are then to be moved to the InitializeComponent method, too. Of course, if they can be generalized, you can write the same kind of method.
The main drawback of this approach is the fact that everything will work until you don't modify your control from the designer, because your InitializeComponent will be messed up. You can control this kind of behaviour by implementing a serializer for your controls. I.e. you have to implement a class BaseControlCodeDomSerializer derived from System.ComponentModel.Design.Serialization.CodeDomSerializer redefining the Serialize method someway like this:
public override object Serialize(IDesignerSerializationManager manager, object value)
{
BaseControl aCtl = value as BaseControl;
if (aCtl == null)
return null;
if (aCtl.Labels == null)
return null;
int num = aCtl.Labels.Length;
CodeStatementCollection stats = new CodeStatementCollection();
stats.Add(new CodeSnippetExpression("CreateLabels(" + num.ToString() + ")"));
return stats;
}
Finally, you can simply associate the Serializer to the Control with this Attribute:
[DesignerSerializer("MyControls.BaseControlCodeDomSerializer", typeof(CodeDomSerializer))]
I was writing a class in c#.
I stumbled upon the this piece of suggestion offered by a code refactor. And i didnt
get what exactly the tool meant when it offered this suggestion/improvement.
Situation :
I was using this.Text property to set the title in the constructor of my Form class.
Form()
{
//some initialization code ...
//...
this.Text = "Non modal form"; //Suggestion offered here..
}
The code refactor tool prompted a warning : saying accessing virtual member
To correct this the tool automatically added a property
public override sealed string Text
{
get { return base.Text; }
set { base.Text = value; }
}
Can anyone explain me how, adding a sealed property will affect/improve the situation.
Cheers
You are calling a virtual member in a constructor. There is no gaurentee that YOUR code will run if the class is inherited and that property is called. Making it sealed prevents this as it can not be overridden in child classes. This shouldn't affect anything in this specific example.
It will help since no derived classes can override it.
As you are dealing with a Form, another option would be to just move your initialization code to the Load event handler (as described by Jon Skeet here):
Load += delegate
{
this.Text = "Non modal form";
};
Using the Load event is much simpler than creating sealed properties, especially if you are accessing more than one virtual property.
Since you are setting a virtual property in your constructor, refactoring tool is suggesting to seal the property so that the value cannot be changed in the inherited classes it cannot be overriden in the inherited classes.
This does not improve performance, nor it makes sense in the scenario you have (a Form). So I would just ignore it.
So we have a C# WinForms project with a Form that contains a bazillion UserControls. Each UserControl naturally exposes all the UserControl methods, properties, etc. in addition to its own specific members.
I've been thinking that one way to reduce the complexity of dealing with these UserControls is to access them through an interface. So instead of drag-and-drop to put the UserControl on the form, something like this in the constructor:
public class MyGiantForm
{
ICustomerName cName;
public MyForm()
{
InitializeComponent();
var uc = new SomeCustomerNameUserControl();
this.Controls.Add(uc);
cName = uc;
}
}
SomeCustomerNameUserControl implements ICustomerName, naturally, and ICustomerName contains the specific properties I really care about (say, FirstName and LastName). In this way I can refer to the UserControl through the cName member and, instead of being bowled over by all the UserControl members, I get only those in ICustomerName.
All well and good, but the problem is that if I do it this way, I can't see SomeCustomerNameUserControl in the Designer. Does anybody know I way I can do this but still see the UserControl on the form's design surface?
EDIT: One way to do this, which isn't overly complicated, is to put the controls on a base form. By default (in C#) the control members are private. Then I create a property for each control exposing it through the interface.
However, I'd be interested in some other way to do this, even if it's more complex. There seems to be some way to do it with IDesignerHost, but I can't find any applicable examples.
If SomeCustomerNameUserControl is defined like this:
class SomeCustomerNameUserControl : UserControl, ICustomerName
{
}
You can still drop this control in the designer (which creates someCustomerNameUserControl1) and do this whenever you need to:
ICustomerName cName = someCustomerNameUserControl1;
Maybe I'm missing something, but I think it's that simple.
There's a way to accomplish what you want -- hiding the members you don't want to see -- but make it apply automatically, without requiring others' cooperation in terms of them using a custom interface. You can do it by reintroducing all the members you don't want to see, and tagging them with attributes.
This is what Windows Forms does when, for example, a base-class property doesn't mean anything for a particular descendant. For example, Control has a Text property, but a Text property is meaningless on, say, a TabControl. So TabControl overrides the Text property, and adds attributes to its override saying "By the way, don't show my Text property in the Property Grid or in Intellisense." The property still exists, but since you never see it, it doesn't get in your way.
If you add an [EditorBrowsable(EditorBrowsableState.Never)] attribute to a member (property or method), then Intellisense will no longer show that member in its code-completion lists. If I'm understanding your question correctly, this is the big thing you're trying to achieve: make it hard for application code to use the member by accident.
For properties, you probably also want to add [Browsable(false)] to hide the property from the Property Grid, and [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] to prevent the designer from writing the property's value to the .designer.cs file.
These will make it very difficult to accidentally use the method/property. They're still not a guarantee, though. If you do need a guarantee, then throw in an [Obsolete] attribute too, and build with "Treat warnings as errors" -- then you're taken care of.
If the base member is virtual, you probably want to override it, and have your override simply call base. Don't throw an exception, since the overridden member will probably be called by the base class during the normal course of events. On the other hand, if the base member isn't virtual, then you want to use "new" instead of "override", and you can decide whether your implementation should call base, or just throw an exception -- nobody should be using your reintroduced member anyway, so it shouldn't matter.
public class Widget : UserControl
{
// The Text property is virtual in the base Control class.
// Override and call base.
[EditorBrowsable(EditorBrowsableState.Never)]
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Obsolete("The Text property does not apply to the Widget class.")]
public override string Text
{
get { return base.Text; }
set { base.Text = value; }
}
// The CanFocus property is non-virtual in the base Control class.
// Reintroduce with new, and throw if anyone dares to call it.
[EditorBrowsable(EditorBrowsableState.Never)]
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Obsolete("The CanFocus property does not apply to the Widget class.")]
public new bool CanFocus
{
get { throw new NotSupportedException(); }
}
// The Hide method is non-virtual in the base Control class.
// Note that Browsable and DesignerSerializationVisibility are
// not needed for methods, only properties.
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("The Hide method does not apply to the Widget class.")]
public new void Hide()
{
throw new NotSupportedException();
}
}
Yes, this is a fair bit of work, but you only have to do it once... per member, per class... umm, yeah. But if those base-class members really don't apply to your class, and having them there will cause confusion, then it may be worth going to the effort.
'I want ICustomerName to be the only option for accessing the UserControl's variable. The idea is that a developer doesn't have to "just remember" to cast it.'
The problem you are having is that you have two completely divergent uses for your form and the controls it hosts. There is no trick built into Visual Studio or winforms which solves this neatly for you. It may be possible, but there is a much cleaner and object oriented way to separate the two methods of interacting with the controls.
If you want to hide the fact that these objects inherit from UserControl, and just want to treat them as IDoSomeThingYouShouldDealWith, you need to separate the logic that deals with the presentation concerns (designer + UI logic) from your business logic.
Your form class, should rightly deal with the controls as UserControls, docking, anchoring etc etc, nothing special here. You should put all the logic that needs to deal with ICustomerName.FirstName = etc into a completely separate class. This class doesn't care or know about fonts and layout, it just knows that there is another instance that can present a customer name; or a DateTime as a 'date of birth choosing' control properly etc.
This is a really lame example, but I have to go right now. You should be able to get the idea covered here in more detail:
public interface ICustomerName
{
void ShowName(string theName);
}
public partial class Form1 : Form, ICustomerName
{
public Form1()
{
InitializeComponent();
}
#region ICustomerName Members
public void ShowName(string theName)
{
//Gets all controls that show customer names and sets the Text propert
//totheName
}
#endregion
}
//developers program logic into this class
public class Form1Controller
{
public Form1Controller(ICustomerName theForm) //only sees ICustomerName methods
{
//Look, i can't even see the Form object from here
theForm.ShowName("Amazing Name");
}
}
After you add the UserControl using the designer, you can set GenerateMember to false in the Properties window to suppress generation of a member.
You could then use some other technique in the constructor to assign your cName reference, e.g.:
foreach(Control control in this.Controls)
{
cName = control as ICustomerName;
if (cName != null) break;
}
cName would then be the only reference to the UserControl.
You could write an extension method that would allow you to return any controls on the form that implement an interface.
public static class FormExtensions
{
public static IDictionary<string, T> GetControlsOf<T>(this Form form)
where T: class
{
var result = new Dictionary<string, T>();
foreach (var control in form.Controls)
{
if ((control as T) != null)
result.Add((control as T).Tag, control as T);
}
return result;
}
}
Then in your form you could call it whereever you want by:
this.GetControlsOf<ICustomerName>()["NameOfControlHere"];
In the event that it returns more than one user control you would need to handle that some how, perhaps by adding Tag property to the interface to uniquely keep track of each user control or something, like so
public partial class UserControl1 : UserControl, ICustomerName
{
public string Tag { get { return this.Name; } }
}
You can then drag and drop the user controls onto your form from the designer. Tag will always return the name of your control, which will allow you to directly access the control through the IDictionary's interface. You're developers could put whatever unique identifier they want in the name of the control, and it would carry through to the interface.
Also, it should be noted that this approach will ALSO allow you to use this on ALL forms in your solution.
The only other thing you would need to do is set your GenerateMember to false.
you could as well do as Bob said but assign all your member variables in the constructor, then you have it in one place.
It almost seems like you want to implement a mediator pattern. Instead of having to deal with each of the bazillion UserControls directly, you'd interact with them through the mediator. Each mediator would define the slim interface you want to see from each control. This would reduce the overall complexity by making your design more explicit and concise. For example, you wouldn't need the 20 properties and 50 methods available on one of your controls. Instead you'd deal with the mediator for that control which defines the 2 properties and 5 methods you really care about. Everything would still show up in the designer, but other parts of your app would not be interacting with those controls -- they'd interact with the mediators.
One of the big advantages to this approach is it greatly simplifies your maintenance. If you decide the MyCrappyUserControl needs to be rewritten because the implementation is bad, you just need to update the mediator class for that control. All the other classes that interact with the control do so through the mediator and would be unchanged.
Ultimately it comes down to discipline: you and your team need to be disciplined enough to use the mediators/interfaces/whatever instead of the directly hitting the controls. Institute an over the shoulder code review by a leader programmer if your team is on the low end of the discipline scale.
Assume that MyUserControl is defined like this:
class MyUserControl : UserControl, IMyInterface
{
// ...
}
Then in your form, you should have something like this:
public class MyForm : Form
{
IMyInterface cName;
public MyForm()
{
InitializeComponent();
cName = new MyUserControl();
Controls.Add((UserControl)cName);
}
}
This way, cName is the only way to access this instance of our usercontrol.