c# Accessing WinForm control properties from another class - c#

How does one access WinForm controls such as ProgressBar properties from another class?
Please see my code below. I know this might not be the best option to expose WinForm class and its members as public but I am trying to clear the concept at this point.
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void button1_Click(object sender, EventArgs e)
{
Class1 c = new Class1();
c.loop();
}
public void PBSetup()
{
progressBar1.Minimum = 0;
progressBar1.Maximum = 100;
}
public void PBUpdate(int recno)
{
progressBar1.Value = Class1.recno;
}
}
}
namespace WindowsFormsApplication1
{
class Class1
{
public static int recno;
public void loop()
{
//How do I access Form1.PBSetup()??
for (recno = 0; recno <= 100; recno++)
{
//How do I access Form1.PBUpdate(recno)??
}
}
}
}

You do not want your business logic (your class) interacting with your UI (your form). The business logic should be agnostic of the presentation layer.
If you want the form to respond to things that happen inside the class, you could consider exposing an Event inside the class that the form could subscribe to, much like it would subscribe to a button's click event. The class instance could fire off the event completely unaware of who might be listening, and any subscribers would be notified.

This looks like a big time code smell :).
You would need an instance of Form1 inside of Class1 in order to PBUpdate.
Something tells me what you are doing is just not right.
Explain what you are trying to do and we can help. Otherwise there is no way to access PBUpdate unless you either made it a static function where you could call it like Form1.PBUpdate() or you had an instance of Form1 within your class Class1

You can change the access modifiers of the progress bar from private to Internal or public , you can do this operation from properties pane .
Keep in mind that you have to pass to the second class the instance of the form and then you can change the value of the progress bar directly from the second class.
However is a tricky solution, the best should be keep the presentation layer implementation separated and work with an event.

I do not recommend to use this method, for simple reason as mentioned here by one of the comments. But if you really want to access that form control, here is how:
1) Select that control and set its access modifier to internal.
2) Assume your form id is "Form1" and control id is "control1"
Inside your method:
Form1 form = (Form1)Application.OpenForms["Form1"];
// form.control1 should now be available.

Related

C# Windows Form Initialize

I have a windows form app with 2 forms, and I need to press a button in form one to go to form 2(this is done already) then form 2 will be able to create an object using the add customer method to add to the system. My question is:
1)if I create an Object in Form 2, how could other forms(form3,form4 etc.) have access to this object? As far as I have learned, I can only call the method through an object.
2)if I created an object in Form1, and other forms inherited from form 1, will this object still work in other forms?
3)Objects can be inhereited or not? is this a good practice in real world?
4) How to allow different forms using one object different method?
A static field or property as suggested in zdimension's answer is possible, of course, but it shouldn't be your first option. There are lots of ways to pass data between forms, and it depends on your application which one is best. For example, one way of doing it is:
class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
public AirlineCoordinator Coordinator {get; set;}
...
}
class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public AirlineCoordinator Coordinator {get; set;}
private void Form1_Load(object sender, EventArgs e)
{
this.Coordinator = new AirlineCoordinator(...);
...
}
...
private void ShowForm2Button_Click(object sender, EventArgs e)
{
using(var form2 = new Form2())
{
form2.Coordinator = this.Coordinator;
form2.ShowDialog(this);
}
}
}
In this hypothetical example, Form1 has a button ShowForm2Button; clicking on this button shows Form2 using the same AirlineCoordinator as is used by Form1.
The usual way to make something available to "everyone" is to use a static field, like this:
public class GlobalStuff
{
public static MyType SomeVariable;
}
Here, the GlobalStuff obviously only ever contains global things, so you could consider making it static too to indicate it will never be instanciated.
Here's what MSDN say about it:
Use a static class as a unit of organization for methods not associated with particular objects. Also, a static class can make your implementation simpler and faster because you do not have to create an object in order to call its methods. It is useful to organize the methods inside the class in a meaningful way, such as the methods of the Math class in the System namespace.

How can I make my Form Control variables acessible to classes other than my Form class?

For example after creating a new Windows Form project I have my class called Form1.cs and from that form I can simply start typing the name of a form control and it will auto populate the form control variable names and I am able to use them in the class. However I have other classes that need to be able to access these form control variables as well, but they are not accessible.
Make them public if they are going to be used in another assembly, or internal if they are going to be used in the same project. Making them static means you don't have to pass your Form1 into the other classes.
Example... Say your Form1 has a string that contains the text you display in the title bar. Making it internal static, like this:
internal static readonly string MsgBox_Title = " Best Application Evar!";
lets you access it from other classes like this:
Form1.MsgBox_Title
It doesn't have to be readonly; that's just an example I pulled from an old app...
If you don't want static variables, you'll have to pass in an instance of Form1.
public class SomeClass
{
private Form1 m_Form1;
public SomeClass(Form1 form1)
{
m_Form1 = form1;
}
private void someMethod()
{
string localValue = m_Form1.SomeMemberStringVariable;
}
}
It's a very contrived example, but hopefully you get the idea.
If you want to call the Refresh method from a class instantiated from Form1, you could use an event in the child class to notify Form1.
Example:
This Form1 has a button that I use to show a secondary form.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnShowPopup_Click(object sender, EventArgs e)
{
PopupForm f = new PopupForm();
f.CallRefreshHandler += PopupForm_CallRefreshHandler;
f.ShowDialog();
}
private void PopupForm_CallRefreshHandler(object sender, EventArgs e)
{
Refresh();
}
}
The secondary form, "PopupForm", has a button that I use to raise an event that the Form1 is subscribed to, and lets Form1 know to call Refresh.
public partial class PopupForm : Form
{
public event EventHandler CallRefreshHandler;
public PopupForm()
{
InitializeComponent();
}
private void btnRaiseEvent_Click(object sender, EventArgs e)
{
EventHandler handler = CallRefreshHandler;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
Hope this helps.
Create an object of that class & start using those variables like this
Form1 fm = new Form1();
string abc = fm.VAR;
Define a public property in your form.
public string MyProp { get; set; }
Form1 frm = new Form1();
frm.MyProp = "Value";
Or define the property as static to avoid having to instantiate Form1:
public static string MyProp { get; set; }
Form1.MyProp = "Value";
I ran into this issue recently. I was keeping some methods in a separate class. Maybe not a good design decision in my case, I'm not sure yet. And these methods sometimes needed to communicate with controls in the main Form1. For example, to write to textBox1.
Turns out easy enough. Just write your method signature to include a TextBox instance. For example you pass textBox1 in and inside the method you refer to it as tb. Then when you call that method (even though it is in another class) you set the tb.Text property to whatever you like and it will show on textBox1.
This makes sense when you consider that control is just a special kind of object, graphically represented in the Form. When you pass it as an argument to a method in another class or the same class, you are actually passing the reference. So writing text to it in the method call will write text to the original control.

Circular dependency when adding reference (Delegates)

Basically I have 2 projects, a form and a user control.
I need both of them to be in different projects but the form need to refer to the user control as it is using the user control. And the user control will need to refer to the form as it is using one of the form class. When I add the second one because it need the , VS will complain circular dependency which is understandable. How do I solve this?
Logically the form should depend on the user control. You could create an interface to replace the form within the user control project, and then have the form implement that interface.
Example user control project;
public interface IForm
{
string MyString { get; }
}
public class MyUserControl : UserControl
{
public IForm Form { get; set; }
private void ShowMyString()
{
String myString = Form.MyString;
...
}
}
Example Form project
public class MyForm : Form, IForm
{
public MYString { get "My String Value"; }
}
I think the root cause of your problem is that you haven't separated your concerns between the form and the control properly.
Since you have a (somewhat generic) control, it shouldn't depend on the form. All of the logic of the control should reside within the control itself. The form should only black-box consume the control: add it, set public fields, call public methods, etc. anything else is a violation of encapsulation.
Sometimes, controls may need to know things about their parent form. In this case, I would suggest something as simple as adding a Parent field to the child control.
if you need something more specific from the form, you can always add an interface; the interface should only list those things that the control needs from the form. For example, if you need the size, you can add:
public interface IControlParent {
int Width { get; }
int Height { get; }
}
This way, you clearly see the dependencies (what the control needs from the parent), and if the parent type/contract changes, you don't need to do as much to change your control class.
You must sepárate your code, its never a good idea to have a reference to an application assembly, if you try to reuse it in the future, the applications exe should go with the control.
So, take the class from the form project and move it to the control project or create a library project, put the class on it and reference it from your control and your app projects.
You should use an event (delegate). Let's assume that inside your form project you created one class: Form1. And inside user control you defined UserControl1.
UserControl1 needs to instantiate and call a method from Form1:
public class Form1
{
public void Execute(string sMessage)
{
Console.WriteLine(sMessage);
Console.ReadLine();
}
}
UserControl1:
public class UserControl
{
public Func<object, object> oDel = null;
public void Execute()
{
oDel?.Invoke("HELLO WORLD!");
}
}
And from the class that instantiate UserControl, let's call it ParentClass:
public class ParentClass
{
public void Execute()
{
UserControl oUserControl = new UserControl();
oUserControl.oDel = Form1Action;
oUserControl.Execute();
}
public object Form1Action(object obj)
{
string sObj = Convert.ToString(obj);
Form1 oForm = new Form1();
oForm.Execute(sObj);
return null;
}
}
This approach gives the responsibility of handling an event to the high level class.

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;

C# Winforms: How to get a reference to Form1 design time

I have a form that has a public property
public bool cancelSearch = false;
I also have a class which is sitting in my bll (business logic layer), in this class I have a method, and in this method I have a loop. I would like to know how can I get the method to recognise the form (this custom class and form1 are in the same namespace).
I have tried just Form1. but the intellisense doesn't recognise the property.
Also I tried to instantialize the form using Form f1 = winSearch.Form1.ActiveForm; but this too did not help
Any ideas?
When you are calling the business logic that needs to know the information pass a reference of the form to the method.
Something like.
public class MyBLClass
{
public void DoSomething(Form1 theForm)
{
//You can use theForm.cancelSearch to get the value
}
}
then when calling it from a Form1 instance
MyBlClass myClassInstance = new MyBlClass;
myClassInstance.DoSomething(this);
HOWEVER
Really you shouldn't do this as it tightly couples the data, just make a property on your BL class that accepts the parameter and use it that way.
I think you should look at how to stop a workerthread.
I have a strong feeling that you have a Button.Click event handler that runs your business logic and another Button.Click that sets your cancelSearch variable. This won't work. The GUI thread which would run your business logic, won't see the other button being clicked. If I'm right you should very much use a worker thread.
Your question is really not clear. You might want to edit it.
Advice
The form shouldn't pass to your business logic layer...
Solutions to your problem
BUT if you really want to (BUT it's really not something to do), you need to pass the reference. You can do it by passing the reference in the constructor of your class, or by a property.
Method with Constructor
public class YourClass
{
private Form1 youFormRef;
public YourClass(Form1 youFormRef)
{
this.youFormRef = youFormRef;
}
public void ExecuteWithCancel()
{
//You while loop here
//this.youFormRef.cancelSearch...
}
}
Method with Property
public class YourClass
{
private Form1 youFormRef;
public int FormRef
{
set
{
this.youFormRef = value;
}
get
{
return this.youFormRef;
}
}
public void ExecuteWithCancel()
{
//You while loop here
//this.youFormRef.cancelSearch
}
}
As the other (very quick) responses indicate, you need to have an instance variable in order to get your intellisence to show you what you need.
Your app by default does not have a reference to the main form instance, if you look at your program.cs file you will see that the form is constructed like so...
Application.Run(new Form1());
so you have a couple options, you could create a global var (yuck) and edit your program.cs file to use it..
Form1 myForm = new Form1();
Application.Run(myForm);
Pass a reference to the business object from your running form like some others have suggested
myBusinessObj.DoThisThing(this);
or find your form in the Application.OpenForms collection and use it.

Categories