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.
Related
I created a C# class that extends Button, but associates a generic type like this:
public class DropButton<T> : Button where T : INamed
{
//contains lots of properties and methods that
//reference and operate on the objects of type T
}
...where INamed interface specifies what properties any class should have to be used with my DropButton:
public interface INamed
{
string Name { get; set; }
bool Selected { get; set; }
}
I can add an instance of the control on a WinForms form programmatically:
private DropButton<MySet> MyDropButton = new DropButton<MySet>();
//Then set properties of the control in the form constructor and add it.
It works splendidly and it keeps my form code a lot cleaner.
However, the new control does not show up in the Toolbox for the project. Nor does the designer recognize the code if I manually modify the .Designer.cs file with an instance of it.
So two questions:
Is there a way to trick the WinForms form designer to allow it in design mode?
Is there a better way to go about this pattern?
I use a TabControl in one of my classes. However, I don't want to bloat this class and put all the code in it, as well as all the XAML for the TabItems.
After some Googling I've come up with the UserControl. So I created a UserControl for every TabItem, with the C# code of the TabItem in this UserControl.
The problem here, is that I need to transfer some data from my parent window (the one containing the TabControl) to the UserControls, to correctly display the data needed for that tab.
I created the UserControl in XAML and the code is like this:
<TabItem Name="userTab" Header="Gebruikers" HorizontalAlignment="Stretch">
<local:UserTabControl x:Name="userTabPanel"/>
</TabItem>
This is the constructor code for my UserControl:
public UserTabControl() {
setUsersView(); // NEED DATA FOR THIS
setUserData((User)usersView.SelectedItem);
InitializeComponent();
}
This is the class variable in the UserControl that needs a variable from the parent window: private static Parser m_config;
When I run this, I get a compile error saying :
"Object reference not set to an instance of an object."
pointing to the XAML line where I create my UserControl.
So, the conclusion here is I am yet unable to pass the variable to the UserControl and would like to have some suggestions or hints or guidance on how to do it in this case. Where am I going wrong here in achieving the required functionality ?
Im not sure that its the best way to do so, but for me it worked well.
For start I create CustomUserControl Class that inherit from UserControl with constractor that get his parent Form as an attribute like this:
public partial class CustomUserControl : UserControl
{
MainForm parentForm;
public CustomUserControl(MainForm mainForm)
{
parentForm = mainForm;
}
...
...
private void doSomthing()
{
parentForm.MainFormMember = 1;
}
}
And in the MainForm:
public partial class MainForm : Form
{
private int MainFormMember{ get; set; }
private CustomUserControl customUserControl;
public MainForm()
{
InitializeComponent();
// Create and add the CustomUserControl manually and not from ToolBox
customUserControl = new CustomUserControl(this);
this.Controls.Add(customUserControl);
}
...
...
}
In this way you can access the Form components from the UserControl
I've tried looking this up and I couldn't find anything that I understood.
But what I'm trying to do is create a class with all my functions in, then call it from the parent form.
And one of these functions contains adding controls to the parent form, but I cannot find out how to do this, can somebody help me please and explain it along the way?
Many thanks,
Jarrod
Typically, I'd just add a reference to the parent form in the lower class and initialize it in the constructor. Something like this:
public form MyForm : Form
{
Foo myFoo;
public MyForm()
{
this.myFoo = new Foo(this);
}
}
public class Foo
{
private MyForm parentForm;
public Foo(MyForm parent)
{
parentForm = parent;
}
}
Then you can reference the parent form and manipulate it how you wish. It also works for static classes, too.
Try this;
In your class use this method to add controls to Parent form
public static void AddControl(Form ParentForm,Control control,Point location)
{
control.Location=location;//This is only to show you
Parent.Controls.Add(control);//how it can be done.You can replace this logic with yours
//but make sure to add this Parent.Controls.Add(control),where control will be the name of your Control.
}
Then whenever you need to add a control call the function as;
ClassName.AddControl(this,new TextBox(),new Point(10,10));//Change ClassName to your class's name.
Anything else please let me know.
I need to call "panel.invalidate" outside my form (WINform) class also I need to change some other controls as well, I read similar question here, and tried what they said, but it didn't work and I wasn't convinced at all.
The answer I read was about exposing a public method like this:
public void EnableButton(bool enable)
{
this.myButton.Enabled = enable;
}
Also I made a static instance in the other file
static Form1 myForm = new Form1();
Any useful suggestions??
The problem is the "myForm" reference. It is a reference to an instance of Form1 that isn't visible and doesn't match the one that the user is looking at. It can't be a match, you created a new one.
Whatever class needs to update the form must have a constructor that takes a Form1 reference. You can create the class object in your Form1 constructor or Load event, pass "this". Using Application.OpenForms[0] is another way to get the reference, one you should not use.
Are you updating from the same thread? Otherwise you might need to use Invoke.
Here's a nice short article about how to do that:
http://blogs.msdn.com/csharpfaq/archive/2004/03/17/91685.aspx
Control.Invalidate() is a public method, but the control itself is most likely not public. You will have to expose the call to Control.Invalidate() through a public facing method in your form or by marking the control in question as public.
public class MyForm : Form {
private TextBox tbxName = new TextBox();
public InvalidateTextBox() {
tbxName.Invalidate();
}
}
OR
public class MyForm : Form {
public TextBox tbxName = new TextBox();
}
public class SomeOtherClass {
public void InvalidateTextBox(MyForm form) {
form.tbxName.Invalidate();
}
}
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.