Lets Say I have a FormBase Class that is inherited from 'Form', and I have winforms Form that inherit from FormBase, how do I get access and manipulate the Controls in the Child Form as follows:
public class FormBase : Form
{
protected FormBase()
{
//for each Control in Child form Controls
//Do something with the Controls
}
}
public partial class Products : FormBase
{
public Products()
{
InitializeComponent();
}
}
You should not access the controls of the child form in the constructor of the base form. Because base constructor will be run first and child constructor after that.
Instead you should do
public class FormBase : Form
{
protected override void OnLoad(EventArgs e)
{
//access the child controls here. Take a look at Will A's answer
base.OnLoad(e);
}
}
Take a look at this question & answers - this should give you what you need, albeit with some adaptation.
Related
I have a main form that acts as a "Wizard" for a bunch of different user controls. I have one user control with relatively basic operations, and I am trying to create a new user control that inherits this basic user control.
However, the base user control has a variable containing the main form (so the user control can access the wizard control functions in the main form). When I create a new "inherited user control" the Designer complains that the reference to the main for has not been set to an instance of the object. I set the reference to the MainForm during runtime when I create an instance of the base user control.
Is there a way to make this work? Below is some simplified code demonstrating my problem.
MainForm.cs:
public partial class MainForm : Form
{
public string exampleString = "From MainForm";
public MainForm()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
BaseControl base = new BaseControl();
base.mainForm = this;
{
}
BaseControl.cs
public partial class BaseControl : UserControl
{
public MainForm mainForm { get; set;}
public TestPanel()
{
InitializeComponent();
string needed = mainForm.exampleString; //Object reference not set to an instance of an object here
}
}
So when I try to create a user control that inherits BaseControl through Solution -> Add -> New Item -> Inherited User Control and select BaseClass, the designer complains of the "Object reference not set to an instance of an object" error at the string needed = mainForm.exampleString line in BaseControl.cs.
Any help with this would be greatly appreciated. Hopefully this is enough information for you to understand what I am trying to do.
Thanks.
The code which you shared will not work, neither at run-time nor in design-time.
You are trying to use mainForm.exampleString in constructor of BaseControl while mainForm will be assigned just after creating an instance of BaseControl.
In such cases, specially when you want to have design-time support, you can derive from ISupportInitialize interface and override BeginInit and EndInit.
Example
The following control implements ISupportInitialize. If you drop an instance of the control on the form, at run-time, it tries to find the parent form and if it was MainForm tries to use public members of the MainForm:
using System.ComponentModel;
using System.Windows.Forms;
public class MyControl : Control, ISupportInitialize
{
public void BeginInit()
{
}
public void EndInit()
{
var parent = this.FindForm() as MainForm;
if (parent != null)
{
//Access to MainForm members
}
}
}
This is just an example that shows how to use ISupportInitialize. In action, it's not a good idea to have a dependency to a specific type of parent form. A better idea as already mentioned in Jimi's comment is relying on interfaces. For example you can have a property of ISomeInterface in your control. The interface should contain the methods or properties which you want to have for the parent of your control. Then implement the interface in some forms. Then after you dropped an instance of your control at run-time or design-time, assign the form to the property.
Problem: When I execute my code it pulls up the code correctly from the inherited base class and changes the text of the base form correctly. But as soon as I, in debugger mode in VS2013, come back into the derived class and step over the InitizlieComponent(); call everything is reverted back. When I say 'reverted back' I mean that thing go back to the way that they were in the designer for the derived form.
All help would be appreciated!
Derived Class
public partial class appSuiteMenu : App.baseForm
{
public appSuiteMenu()
: base("App Suite")
{
InitializeComponent();
}
}
Base Class
public partial class baseForm : Form
{
public baseForm() { InitializeComponent(); } //Required or designer breaks
public baseForm(string formTitle=null)
{
this.initialize(formTitle);
}
private void initialize(string formTitle)
{
base.text = formTitle + " - " + //Other objects are called from the class
}
public override string Text
{
get
{
return base.Text;
}
set
{
base.Text = value;
}
}
}
My guess would be the second call to the "InitializeComponent()" inside the derived class.
What is does, is exactly what you said. It overrwrites everything from the base initialization.
I believe you can remove it and it'll be fine:
public appSuiteMenu()
: base("App Suite")
{
}
Read more about it in here: http://www.dotnetperls.com/initializecomponent
Edit:
Here is some tests I did with two forms. One is derived from the other. The base form hase a label. The second from adds another label. When creating a form of the derived type, tou get a form with two labels. What I did was use InitializeComponent(); in both base and derived forms.
The code:
public partial class BaseForm : Form
{
public BaseForm()
{
InitializeComponent();
label1.Text = "asdf";
}
}
...
public partial class DerivedForm : BaseForm
{
public DerivedForm()
{
InitializeComponent();
label2.Text = "asdfasfd";
}
}
What happens in execution of the code is that the base initialization happens. Then the derived initialization adds only the add functionality.
It seems pretty straightforward, but Iv'e noticed you had only one InitializeComponent(); in the code above that will actually happen.
Dave,
Your edited posted is nearly what I ended up doing to correct my problem. Since I was overriding the .Text() property of the base form, I found that I didn't even have to pass anything in the constructor. Simply setting the form text in the code, or designer, changed everything for me.
This question already has answers here:
How can I get Visual Studio 2008 Windows Forms designer to render a Form that implements an abstract base class?
(10 answers)
Closed 8 years ago.
I have designed 3 different win forms in c#.
public partial class SLOSPR : form
{
public bool IsCallable;
public void PopulateData();
}
public partial class SLOFIX : form
{
public bool IsCallable;
public void PopulateData();
}
public partial class SPDBID : form
{
public bool IsCallable;
public void PopulateData();
}
I have declared one member variable IsCallable in every form's class and a member function PopulateData() in every form's class. It is so because, in a code segment I want to declare one variable of a form type, and want to assign an object of any of the above 3 classes and use that IsCallable variable and call PopulateData().
like this:
public form RetForm()
{
form frm=new /* constructor of any 3 forms mentioned above*/
//this function can return any of the three types which will be decided at run time.
return frm;
}
form frm=RetForm();
here i want to use IsCallable and call PopulateData().
like this:
if(frm.Iscallable)
frm.PopulateData();
Which is not possible syntactically as Iscallable and PopulateData is not member of form class
To solve this problem I extended the form class to an abstract class and declared those 3 forms from the extended class.
public abstract class EXTENDED_FORM : form
{
public bool IsCallable;
public abstract void PopulateData();
}
and changed the definition of those 3 forms like this.
public partial class SLOSPR : EXTENDED_FORM
{
public override void PopulateData()
{
/*body for SLOSPR */
}
}
public partial class SLOFIX : EXTENDED_FORM
{
public override void PopulateData()
{
/*body for SLOFIX */
}
}
public partial class SPDBID : EXTENDED_FORM
{
public override void PopulateData()
{
/*body for SPDBID*/
}
}
Now I did like this:
public EXTENDED_FORM RetForm()
{
EXTENDED_FORM frm=new /* constructor of any 3 forms mentioned above*/
//this function can return any of the three types which will be decided at run time.
return frm;
}
EXTENDED_FORM frm=RetForm();
Now I can call like this:
if(frm.Iscallable)
frm.PopulateData();
Automatically overridden PopulateData will be called.
Finally I made my purpose. But as I changed
public partial class SLOSPR : form /*[Designer generated code]*/
to
public partial class SLOSPR : EXTENDED_FORM
The GUI designer in Visual Studio gets messed up, showing the following page.
How to get rid of this, also my purpose gets fulfilled without hampering the designer???
don't make EXTENDED_FORM abstract; remove abstract from its declaration and add protected constructor without parameters
My winform application contains usercontrols and forms.
Each usercontrol inherits a base usercontrol and each form inherits a base form.
The base usercontrol and the base form contain exactly the same properties and methods because what I want is to manage security and language settings at one single place.
This solution is working but I would like all my controls (usercontrols and forms) to inherit a unique base control in order to have these methods at one single place.
Is there a way to achieve this ?
Thanks !
Inheriting in this case doesn't make much sense from an OO perspective.
I suggest creating "SecurityManager" and "LanguageManager" classes and using them from your base form & usercontrol. They will have a clear role and let you control the logic from a single place.
I've run into this issue before. Unfortunately, since C# doesn't support multiple inheritance, your BaseForm and BaseUserControl cannot inherit from BaseFunctions, and Form and UserControl (respectively).
The work around I use is to create a IBaseFunctions interface with the methods needed and place the functionality in a helper class.
You still have a lot of copy-pasta, but at least it's just the wrapping and not the needed logic.
ex:
public interface IBaseFunctions
{
IUser GetCurrentUser();
void ShowMessage(String message);
}
public class BaseFunctionsHelper : IBaseFunctions
{
public IUser GetCurrentUser()
{
// Get Current User
}
public void ShowMessage(String message)
{
// Show message
}
}
public class BaseForm : Form, IBaseFunctions
{
private readonly IBaseFunctions _helper = new BaseFunctionsHelper();
public IUser GetCurrentUser()
{
return _helper.GetCurrentUser();
}
public void ShowMessage(String message)
{
return _helper.ShowMessage(message);
}
}
public class BaseControl : UserControl, IBaseFunctions
{
private readonly IBaseFunctions _helper = new BaseFunctionsHelper();
public IUser GetCurrentUser()
{
return _helper.GetCurrentUser();
}
public void ShowMessage(String message)
{
return _helper.ShowMessage(message);
}
}
I need to add shared functionality to both Forms and UserControls. Since multiple inheritance isn't supported in .net I wonder how I best tackle this?
The shared functionality is a dictionary that is filled by the form or usercontrol and then processed.
Regards
public class SharedFunctionality
{
public void ImportantToCallThisOnLoad();
}
public class MyForm : Form
{
SharedFunctionality mySharedFunctionality = new SharedFunctionality();
public void OnLoad()
{
mySharedFunctionality.ImportantToCallThisOnLoad();
}
}
public class MyControl : Control
{
SharedFunctionality mySharedFunctionality = new SharedFunctionality();
public void OnLoad()
{
mySharedFunctionality.ImportantToCallThisOnLoad();
}
}
Instead of having the Forms & UserControls inherit from a base class can you encapsulate the logic inside of a self contained object so that each form will new up? Then you can limit in the base class just the instantion and interaction with this object which hopefuly is minimal so having it done twice isn't a big deal.