c# Forms Project: Passing Information to User Control - c#

I have created a forms application which uses a TabControl. For each tab I want to place a single UserControl (created in the same project) which contains all the other controls. However, I will need to pass some information from the primary form to the UserControl for it to work property with events, methods, etc. How can/should I do this?
I tried creating a constructor with parameters but then Designer fails and I have to go in and delete out the added UserControl references.
Thanks!

The constructor parameter is the correct method. However, there must still be a default constructor in order for the Designer to be able to construct (and draw) a copy of the object.
My usual workaround is to put a clause in the default constructor, checking to see that we are in "design mode" and throwing an exception if not:
public class MyForm: Form
{
public MyForm()
{
if(!DesignMode) throw new InvalidOperationException("Cannot use default constructor in production code");
}
public MyForm(MyDependency dependent)
{
...
}
}

you can pass information by a function that created in usercontrol.cs file.
for example in usercontrol.cs
public string name;
public void SetName(string pname)
{
this.name = pname;
}
or maybe you want to change button name
Button mybutton = new Button();
public void SetButtonName(string btname)
{
this.mybutton.Text = btname;
}
Now you can call these functions in your mainform.cs
Myusercontrol usc = new Myusercontrol();
usc.SetName("this is string for 'name' string");
usc.SetButtonName("this is string for button text");

Try creating your constructor, but also creating a default parameterless constructor.
Take a look at this question

Related

Passing Variable from another class into a form

I am struggling with passing a Variable (a string) in C# for a special problem:
Overview:
I am writing a plugin for a purchased program at my company. The program (or better: the programs support) gives the user basic C#-Code which basically just opens a form, and connects the program with whatever I write down in the forms code.
As it is a Visual-Studio-Solution I get some files: "MyUserInterface.cs" and "MyUserInterface.Designer.cs".
"MyUserInterface.Designer.cs" defines the look of my form, i thing the most importand parts for my problem are:
partial class MyUserInterface
{
[...]
private void InitializeComponent()
{
[...]
this.f_status = new System.Windows.Forms.Label();
this.SuspendLayout();
[...]
//
// status
//
this.f_status.Name = "status";
this.f_status.Text = "WELCOME TO MYPLUGIN v2";
[...]
this.Controls.Add(this.f_status);
this.ResumeLayout(false);
this.PerformLayout();
}
[...]
private System.Windows.Forms.Label f_status;
[...]
}
The most important code from "MyUserInterface.cs" is:
partial class MyUserInterface
{
[...]
public MyUserInterface()
{
InitializeComponent();
}
[...]
private void click_compute(object sender, EventArgs e)
{
//Basically everythings runs here!
//The code is opend in other classes and other files
}
}
Now as i marked in the code section, my whole code runs in the "click-compute" Function and is "outsourced" into other classes.
One important part of my code is found in "statushandler.cs":
class statushandler
{
[...]
public static void status_msg(string c_msg)
{
[...]
f_status.Text = c_msg; // And here is my problem!!
[...]
}
}
Problem:
In my special case, i try to change the text of the "f_status"-Lable while running my code by using the "status_msg" Function!
While I pass variables between classes a few times in my code. A cannot figure out, why this explicit one cant be found inside "statushandler". (It is no problem as long as I stay inside the original "click_compute", without going into a different class).
What I already tried:
1.) I tried to change basically everything in "MyUserInterface" into "public",
2.) Also I tried to call f_status in status_msg like MyUserInterface.f_status.Text,
3.) Write a Getter/Setter-Function in "MyUserInterface.(Designer.)cs" (both), which was catastrophic because i couldn't define the Label in the InitializeComponent anymore.
4.)
a.)Read a lot of Stackoverflow-Threads about passing variables between classes, which all didn't helped, all solutions I found, are working between classes, but not in this special case.
b.)Watched a lot of youTube tutorials, same result.
c.)Read some stackoverflow-Threds about passing variables between different Forms, but they all had in common, that the "displaying-form" was opend AFTER the variable was known. In my special case the form is opened all the time, and can't be closed, nor reopened...
And now I am out of ideas!
I wouldn't be surprised, if I do not see some details, but I can't found them... I would be very happy, when somebody could help me!
My question:
How can I change the text of my lable from another class?
Your method is static while your form has instance. So your static method does not know anything about your form. You can add MyUserInterface parameter to static method
public static void status_msg(MyUserInterface form, string c_msg)
{
[...]
form.f_status.Text = c_msg; // And here is my problem!!
[...]
}
If you have single instance form (only one instance is created at a time) you can have static property with it's reference:
partial class MyUserInterface
{
public static MyUserInterface Instance { get; private set; }
[...]
public MyUserInterface()
{
InitializeComponent();
Instance = this;
}
}
With this solution you can use your old method:
class statushandler
{
[...]
public static void status_msg(string c_msg)
{
[...]
MyUserInterface.Instance.f_status.Text = c_msg; // You have instance of yout form here
[...]
}
}
Of course you should protect against null/ Disposed form etc.
Create a public property on the specific class in your 1st Form that gets the label's value like this:
public string Name {get {return Label1.Text}; set {Label1.Text = value}; }
Then in your 2nd Form:
public Form2(Form1 form)
{
string name;
name = form.Name;
}

Calling method from different namespace and class

I'm trying to put some stuff that I use a lot into separate classes so it's easier to implement when starting a new project.
One of the things that I would like to do, is dynamically create a statusbar on my mainform. I have done this in a previous project and there it worked fine. So I copied the code and I changed the NameSpace for the mainform.
When I run the code it stops at the line
MainForm.Controls.Add(status);
When I look, it says Mainform is null.
Other than the Namespace I haven't changed anything.
Does anybody have an idea why this is happening?
Thanks
Kenneth
//THIS IS THE SEPARATE CLASS
public class Tools
{
public Form MainForm;
public void setupForm()
{
// LINK THE FORM
MainForm = myNamespace.Form1.MainForm;
// CREATE A STATUSBAR
StatusStrip status = new StatusStrip();
status.Name = "status";
// I'VE REMOVED SOME OF THE DYNAMIC CREATION STUFF FOR READABILITY
// ADD THE STATUSSTRIP TO THE FORM
MainForm.Controls.Add(status);
}
//THIS IS THE MAINFORM
public static Form1 MainForm;
public myNameSpace.Tools tools;
private void setupForm()
{
this.KeyPreview = true;
// LINK THE TOOLS CLASS
tools = new myNameSpace.Tools();
// SETUP THE FORM
tools.setupForm();
}
You have to pass a refernece of your main form to the Tools class. You can do this when you initialize tools or when you call the method setupForm. I implemented the second possibility for you:
//the call:
tools.setupForm(this);
//the implementation of the method
private void setupForm(Form1 MainForm)
{
//your method code
}
The normal way to separate responsibility is to inject the object you want to affect - not hijack it with a hardcoded reference.
Try injecting the form when you create your tools object:
tools = new myNameSpace.Tools(this);
Its null because you don't initiate or have a refference to the main window. You just create an alias for the namespace but not for the instance.
Pass the mainWondow as a parameter to the setupForm function. Then it will work.

Error adding panel to usercontrol: Object reference not set to an instance of an object

I have a problem. I am trying to access a panel in a user control.When I access it in a form it works. Earlier on I did this.
I accessed a panel in a form from a user control and it worked. Below is the code I used:
Form1 form = Application.OpenForms.OfType<Form1>().FirstOrDefault();
form.Panel1.Controls.Clear();
ManageControl user = new ManageControl();
form.Panel1.Controls.Add(user);
But when I try to use the very same concept in a user control it does not work.
It throws a null error: Object reference not set to an instance of an object.
Below is the code:
//this is in ManageControl.cs
public Panel Panel2
{
get { return panelmanage; }
}
//this is in another userControl.Trying to access panelImage
ManageControl form = Application.OpenForms.OfType<ManageControl>().FirstOrDefault();
form.Panel2.Controls.Clear();//it throws the error here
ReportControl user = new ReportControl();
form.Panel2.Controls.Add(user);
What am I doing wrong because I am using the same concept?
EDIT:
This is my ManageControl.cs
public partial class ManageControl : UserControl
{
public ManageControl()
{
InitializeComponent();
}
public Panel Panel2
{
get { return panelmanage; }
}
This is how I try to access it in BookingListControl
public partial class BookingListControl : UserControl
{
ManageControl form = Application.OpenForms.OfType<ManageControl>().FirstOrDefault();
public BookingListControl()
{
InitializeComponent();
}
private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
ManageControl form = Application.OpenForms.OfType<ManageControl>().FirstOrDefault();
ReportControl user = new ReportControl();
form.Panel2.Controls.Add(user);
}
ManageControl is a UserControl not a Form. Thus, when you look for open forms of type ManageControl, you get nothing (no surprises here). Then, we you call FirstOrDefault it returns null (since there were no matching elements in the empty collection), and your next line blows up.
This approach is doomed from the start, because even if you had a whole bunch of forms overlaying each other and could make it work (bad idea), it would break once you had two ManageControl objects and needed to access the second.
Instead, first ask yourself, "Why do my UserControl objects need to access each other?". This is an important question, because in general UserControls are independent. They likely have methods to give data back to their parent, but thats it. They certainly don't interact with other UserControls.
If you decide that you really need this dependency, then I would pass the parent Form object to both UserControls and have a public property on the Form that allows them to see the other UserControl. From here you can access it normally (without needing any OpenForms nonsense). Honestly though, this is a massive code smell and it sounds like the whole design should be looked at to see where you have dependencies that could be removed.
To do this you need to expose the ManageControl on the form:
public class ParentForm : Form
{
public ManageControl Manager { get { return manageControlInstance; } }
...
}
Then access it in your child control. The easiest way would be through the Parent property, but you could pass it on the constructor or an Init function as well.
public class ChildControl : UserControl
{
private void SomeFunction()
{
(Parent as ParentForm).Manager.Panel2.Controls.Add(new ReportControl());
}
}
The code's pretty ugly, and I wouldn't recommend it (its also not safe if you put the ChildControl into anything other than a ParentForm). That being said it would work.
Assuming that the NullReferenceException occurred based on accessing the "Panel2" property, your issue is that "panelmanage" is null. Is the code that finds and populates "form.Panel2" in a form or control constructor? If so, try restructuring it to run after ManageControl is fully initialized - perhaps by putting it into a Loaded event.

Passing values between two windows forms

The case is this, I have two different forms from the same solution/project. What I need to do is to extract the value of a label in Form A and load it into Form B. As much as possible, I am staying away from using this code since it will only conflict my whole program:
FormB myForm = new FromB(label.Text);
myForm.ShowDialog();
What I am trying right now is a class with a property of get and set for the value I wanted to pass. However, whenever I access the get method from FormB, it returns a blank value.
I hope somebody can help me with this. Any other ways to do this is extremely appreciated. :)
public class Miscellaneous
{
string my_id;
public void SetID(string id)
{
my_id = id;
}
public string GetID()
{
return my_id;
}
}
You could do something like this:
Child form
public string YourText { get; set; }
public TestForm()
{
InitializeComponent();
}
public void UpdateValues()
{
someLabel.Text = YourText;
}
Initiate it
var child = new TestForm {YourText = someTextBox.Text};
child.UpdateValues();
child.ShowDialog();
With this approach you don't have to change the Constructor, you could also add another constructor.
The reason for them being empty is that the properties are set after the constructor, you could Also do someting like this to add a bit of logic to your getters and setters, However, I would consider not affecting UI on properties!
private string _yourText = string.Empty;
public string YourText
{
get
{
return _yourText;
}
set
{
_yourText = value;
UpdateValues();
}
}
In this case, the UI will be updated automaticly when you set the property.
You can use a static variable/method to hold/pass the value of a control (when it gets changed).
You can use form reference or control reference to get and pass values directly.
You can use custom event for that (notifying the code that subscribed).
btw. FormB myForm = new FromB(label.Text); did not work because you are passing by value and the value was empty at the moment of creation of FormB.
FormB myForm = new FromB(label); would have worked.
Well one approach to take is to create a singleton class in your application. When you form b loads or the label changes you update the singleton with the value. Then when form a needs the value it can just get the instance of the singleton within your application and it will have that value.
There are probably cleaner ways to do it but just thinking of an easy way to pass information back and forth and store any information needed for both forms.
EDIT: Here is an example of a singleton that I pulled from here:
http://www.yoda.arachsys.com/csharp/singleton.html
public sealed class Singleton
{
static readonly Singleton instance=new Singleton();
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Singleton()
{
}
Singleton()
{
}
public static Singleton Instance
{
get
{
return instance;
}
}
}
Now all you need to do is put this class in a namespace that is accessible to both forms and then you can call the Instance property of this class and then reference your values. You can add properties to it as well for whatever you want to share. When you want to retrieve those values you would call it like this:
Singleton.Instance.YourProperty
((Form2)Application.OpenForms["Form2"]).textBox1.Text = "My Message";
declare public property varible in second form
Public property somevariable as sometype
and access it in first form using instance
Dim obj as New form2()
obj .somevariable ="value"

C#: How to access a button outside the form class

I want to either enable or disable a button from another file,what should I do?
This is the form class declaration:
public partial class Form1 : Form
I tried with
Form.btnName.enabled = false/true
but there's no btnName member.
Thanks in advance!
Simply expose a public method:
public void EnableButton(bool enable)
{
this.myButton.Enabled = enable;
}
Correction:
public void EnableButton()
{
this.myButton.Enabled = true;
}
You need to expose the btnName member to other classes by making it public or using a property of sorts. For example add the following code to Form1
public Button ButtonName { get { return btnName; } }
Now you can use form.ButtonName for any instance of Form1
I really suggest to read more information on how forms fit in .net. You have a couple issues in that sample code "Form.btnName.enabled = false/true"
Your form is called Form1, it inherits from Form.
Forms are instances, in fact you can have different form instances in an application belonging to the same class.
Because of the above, it would not make sense to access Form1.btnName. You have to do it through the specific instance.
Form's controls are not public by default, define a method for that.
Windows forms projects, usually have a main that runs the form. There you can access the form instance and hand it to something else in the app.
The above answers the specific question. Note that there are multiple ways to achieve different scenarios, and what you really want to do might not need the above approach.
This is because by default, the controls on a form are not public (unlike in VB6 which all controls were exposed publicly).
I believe you can change the visibility accessor in the designer to public, but that's generally a bad idea.
Rather, you should expose a method on your form that will perform the action on the button, and make that method accessible to whatever code you want to call it from. This allows for greater encapsulation and will help prevent side effects from occurring in your code.
You'll have to specify it on your specific instance of Form1.
Ie: If you have something like Form1 myForm = new Form1(...);, then you can do myForm.btnName.Enabled = false;
This will also require that btnName is public. It would be "better" to make a property or accessor to retrieve it than directly provide public access to the, by default, private button field member.
You need to add a public property, or method to set the button.
public void DisableBtnName()
{
this.btnName.Enabled=false;
}
public Button BtnName
{
get { return this.btnName;}
}
In Form1, create a object for external class(add button name in the parameter)
Class1 obj_Class1 = new Class1(btnName);
In Class1 , create a private button
private System.Windows.Forms.Button btnName;
In Class1 Construct
public Class1(System.Windows.Forms.Button btnName)
{
this. btnName = btnName;
}
then you can access your button like,
btnName.enabled = false/true;

Categories