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);
Related
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!
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 need to get a name of object's instance at runtime. I have a way of doing it but I think there must be a better way.
Let's say I have 4 forms: FormA1, FormA2, FormA2 and DormA4. They all derive from FormA. FormA never gets instantiated - let's say it is virtual.
I also have FormB. Each of the FormA children can at runtime, upon certain event, instantiate FormB. FormB's job is to take some information and return it to the form that called it (instantiated it) at runtime. But without knowing the name of calling form's instance I can't access any of calling form's properties.
The way I currently do it is I have a constructor in FormB that takes a reference to sender as argument using FormA as type, example:
public class FormB : Form
{
private FormA referenceForm;
public FormB(ref FormA callingForm)
{
referenceForm = callingForm;
}
}
this way I can hale local methods access properties of calling form. Of course to get specific properties I need code reflection so I would get the right type and access to specific properties of children.
Alternatively, I think, I could create FormHandler class, instantiate it every time child form gets instantiated and pass values inside events but this may make it more complicated than necessary.
So the question is, how do you get instance name of an object so you can access its properties?
You haven't explained why and when you need to do this but it sounds like you're looking for the publisher-subscribed pattern. You can use delegates/events for this e.g here FormB publishes interesting events to FormA
public class InterstingInfo
{
// TODO
}
public class FormB
{
public delegate void Callback(InterstingInfo interestingData);
public event Callback observer;
private void NotifyObserver()
{
InterstingInfo interstingInfo = null;
// TODO setup intersting data
observer.Invoke(interstingInfo);
}
}
public class FormA
{
void CreateFormB()
{
FormB formB = new FormB();
formB.observer += (o) => { DoStuffForOtherForm(o); };
}
void DoStuffForOtherForm(InterstingInfo interestingData)
{
// TODO - Do stuff based on 'interstingInfo'
}
}
Is this what you want?
obj.GetType().Name
This will tell you the name (e.g. FormA1)
As an aside, there is no need to use ref in your constructor.
This isn't a direct answer to your question. But you should be using a delegate system. Setup a delegate in FormB that the instantiator of FormB can assign an action to. You can pass the required parameters through the delegate.
See this for more info: https://stackoverflow.com/a/639366/2696641
Where do I use delegates?
FormB should be able to be instantiated anywhere and ideally not care or know about who created it. A better approach for you would be to expose whatever properties you need available in FormB and let the calling object read them.
Well...
I think you're asking for a specific answer. When you should be asking a general... how should I do this.
I would expose all the data your FormAs need from the FormB as properties on FormB. Then I would expose an event on FormB so that FormA knows when to populate itself from B.
http://msdn.microsoft.com/en-us/library/ak9w5846.aspx
This is basically the GOF Observer pattern...
I guess in the end I could just instantiate each of the FormAs to the same name at the runtime, regardless of the form and refer to that arbitrary single name. That as long as I do not instantiate FormAs concurrently.
In C#, a common pattern that I use is to populate the details of a lower calculation class with a form object.
The constructor for MyForm is:
MyForm()
{
_MyFormCalcs = new MyFormCalcs(this);
}
But I encountered an error today which makes me think that as my constructor had not finished completing, it creates a new instance of MyForm to pass into MyData. Thus it calls the constructor twice. I found that a static list in MyFormCalcs was being filled twice and was failing the second time as the keys were already present in the list.
Can I use this in the constructor to refer to this instance? What will it contain in the lower class - has the constructor been run or not.
What is a better way of passing my form into the lower class?
No, that won't create a new instance of MyForm.
In general, allowing this to "escape" from a constructor is dangerous as it means it can be used before the constructor has completed, but it's not going to be creating a new instance. If you could give a short but complete example of the problem you've seen, we could help diagnose it further. In particular, it's not clear what you mean about the "static list being filled twice". Usually it's not a good idea to populate a static variable in an instance constructor.
In fact, it is really nice to avoid such call inside constructor, because your object is not already built (constructor hasnt finish its work) but you are already use this "unfinished" object as a parameter. Its a bad way. Good way is creating some special method:
class MyClass
{
var obj:SomeClass;
public MyClass()
{
}
public Init()
{
obj = SomeClass(this);
}
}
Make a private property that instantiate MyFormCalcs only when it is first used, like this:
public class MyForm {
private MyFormCalcs MyFormCalcs {
get {
_MyFormCalcs = _MyFormCalcs ?? new MyFormCalcs(this);
}
}
}
This way, you don't have to think about when to "initialize" things.
There is this very complete response of C# constructor order:
C# constructor execution order
Hey! I've made a little boiler system that's controlled entirely by a form. The form components, however, call functions in a class for the boiler, radiators and so on.
I've got a little main class to that instantiates all of the classes but I'm struggling to figure out how to pass the form object to those classes so that they can access the form's components.
I guess I should be using mutator methods in each class to store the form object? How would I do this that's syntactically correct?
Thank you! ;o)
Just pass the form to each class. Store it in a private variable so the class can use it later. It is passed by reference by default.
class Boiler {
private Form parentForm;
public Boiler(Form f) {
parentForm = f;
}
}
When you pass a reference type to a method, C# (by default) will pass a copy of the reference to the method. This means that if pass the reference you have to your classes you are giving the method a copy of that reference and since both copies reference the same object both the call site and the method will have access to the same instance.
For example:
class Example
{
static void Main()
{
string s = "hello, world";
// Here we are passing a copy of the reference
// stored in "s" to "Print"
Print(s);
}
static void Print(string str)
{
// By default, "str" will be assigned the copy of the
// reference passed to this method.
Console.WriteLine(s);
}
}
I would be careful building an application in which your domain objects (in your case, Boiler, Radiator, etc.) know about the UI layer that consumes them. If you find that you need to pass a Form to one of these domain models you are probably doing something wrong. If you show us a small example of what you are trying to accomplish we might be able to help you come up with a more maintainable solution.