This might be a novice question. :). Consider the following scenario.
Suppose we have two windows forms that are already "loaded" (i.e You
can see both the forms)
Form 1 contains a textbox and a "submit" button while the form 2
contains a text lable.
The user can enter a string in the textbox and press submit on
form 1 The lable on form 2 should
be updated with the new text.
What is the best way to achive this? Any formal way to do this? I don't want to increase the variable scopes unnecessarily.
Edit : Both the forms belong to same application
Assuming these forms are part of the same application, you need to have a common data model where you keep your data and then your forms "bind" to this data model. Check out M-V-C or M-V-VM patterns. This would also nicely separate your UI from your data.
Do some research on model view controller pattern and databinding in winforms.
Create a seperate controller class and reference this in the two forms, which implements INotifyPropertyChanged. On the controller, have a property which propagates the changed events from and to the forms.
Form1 triggers Form2 to open. Form2 has overloaded constructor which takes calling form as argument and provides its reference to Form2 members. This solves the communication problem. For example I've exposed Label Property as public in Form1 which is modified in Form2.
With this approach you can do communication in different ways.
Download Link for Sample Project
//Your Form1
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 frm = new Form2(this);
frm.Show();
}
public string LabelText
{
get { return Lbl.Text; }
set { Lbl.Text = value; }
}
}
//Your Form2
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private Form1 mainForm = null;
public Form2(Form callingForm)
{
mainForm = callingForm as Form1;
InitializeComponent();
}
private void Form2_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
this.mainForm.LabelText = txtMessage.Text;
}
}
alt text http://ruchitsurati.net/files/frm1.png
alt text http://ruchitsurati.net/files/frm2.png
Related
In C# I have two forms "Form1" and "Form2". Form1 creates images that are stored in a folder. Form2 displays the number of images in that folder.
Say I have made 2 images with Form1 and then I open Form2. Form2 now says there are 2 images. Now while keeping both forms open I want to be able to add a new image and Form2 updates. At the moment if I use Form1 to add more images while Form2 is open Form2 continues to display the number of images that were in the folder when Form2 opened.
I have found solutions that involve Form2 closing and reopening but I don't want this. It's jarring for the user having windows opening and closing every time they press a button. I just want Form2 to update live as I make changes with Form1.
Any help would be greatly appreciated!! Thanks!
You can do this with public method in Form2
In Form1 you need to save Form2 object in property
FORM 1
public partial class Form1 : Form
{
public Form2 MyProperty { get; set; }
public Form1()
{
InitializeComponent();
}
// for opening form 2
private void button1_Click(object sender, EventArgs e)
{
Form2 f2 = new Form2();
f2.Show();
MyProperty = f2;
}
// adding new image
private void button_ADD_Click(object sender, EventArgs e)
{
MyProperty.updateCounter();
}
}
When you add new image, then you can call the metoh from Form2 to update counter.
In FORM 2 you need crate PUBLIC method to update counter
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
// default value
label1.Text = "0";
}
// update counter
public void updateCounter()
{
label1.Text = (int.Parse(label1.Text) + 1).ToString();
}
}
You may want to take a look at events and delegates. Basically, whenever you do something to Form1 that can affect other forms, you want to trigger an event. In Form2, you have a method which you call whenever that event triggers. This way you can have multiple forms open, and as long as you set them to "listen" to a given event, they can all react.
You can read more about them here, in the Microsoft Documentation.
I have created dashboard consisting of two windows - home screen (the Form) and data screen (the User Control).
My home screen is the dashboard and upon clicking on "data" button present on the dashboard, the user is sent to the data screen (where he enters his details) . The way I'm doing this transition between the 2 windows is by making the data screen visible and bringing it to front when data button is pressed.
Q1. Is this the right way to go about switching windows? Is there a better method to do this?
Coming to the main question, the dashboard indicates whether the user has entered data or not and if yes, the user data is displayed. The code to fetch the user data is written in the user control. Now I wish to send this data to the home screen (form) so that the data can be displayed on the dashboard.
Q2. How to link the user control and form - variables wise? How to establish a Bidirectional Communication between form and user control i.e. User control should be able to read form's variables and form should be able to read user control's variables
Here are two approaches...
Tightly Coupled
In UserControlA, I've declared a property of type Form1 (the parent form):
public partial class UserControlA : UserControl
{
public UserControlA()
{
InitializeComponent();
}
private Form1 f1;
public Form1 F1
{
get { return f1; }
set { f1 = value; }
}
private void foo()
{
if (f1 != null)
{
// ... do something with "f1" ...
}
}
}
Then, in Form1, I set that property in the Load() event:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
userControlA1.F1 = this;
}
}
This is tightly coupled because now UserControlA has a hard-coded reference to Form1. This makes it work well with Form1, but is now less flexible as it won't work well with any other forms. If you wanted this approach to work with Form2, for instance, then you'd have to change the hard-coded type in the UserControl.
Use this approach if there is a very strong relationship between the form and the usercontrol and it's likely that the usercontrol will not be used with any other forms, or in any other scenarios.
Loosely Coupled
In UserControlB, I've declared an event (BroadcastName) that will communicate a string to the outside world:
public partial class UserControlB : UserControl
{
public delegate void dlgBroadcastName(UserControlB source, string name);
public event dlgBroadcastName BroadcastName;
public UserControlB()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (BroadcastName != null)
{
BroadcastName(this, textBox1.Text);
}
}
}
Now, in the Load() event of Form1 (or using the lightning bolt icon in the properties pane), we wire up that BroadcastName event:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
userControlB1.BroadcastName += UserControlB1_BroadcastName;
}
private void UserControlB1_BroadcastName(UserControlB source, string name)
{
// ... do something to Form1 with the received information in here ...
}
}
This is loosely coupled because UserControlB has no idea who it is communicating with. It simply raises its event and whoever has subscribed gets notified. Note that this UserControl can be used with any form, without change. This is generally a more flexible approach and makes sense when your usercontrol is more generic in nature and will be used in a wider variety of situations.
I am trying to have a button in Form3 change a label's text in Form1 and Form2.
I have gotten it to work somewhat but in order to have the label change I have to have the mouse click on it. This is my current code in form 1 and 2:
label1.Text = Form3.myNameClass.myName;
and this is code in form 3
public class tournamentNameClass
{
public static string tournamentName;
}
public void button1_Click(object sender, EventArgs e)
{
myNameClass.myName = textBox3.Text;
}
How can I make it so that I dont need to press the label to get it to change?
Since you are at the start of learning, I'm not going to go in events and delegates.
My example demonstrates how you manipulate a control on Form1 from Form2 directly. You should be able to figure this out for Form3 easily by yourself, and is together a good practice of understanding.
(I want to state that there are many different methods/techniques for passing data or manipulate controls between forms, I guess this is the easiest one for you to understand as a beginner, as this is the most simplistic approach of all)
Form1 Designer
First we make label1 its modifier to Public (so we can reach it in another class) in the designer like so:
Form1 code behind
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// With the keyword "this" we pass in Form1, the current instance we are in
Form2 form2 = new Form2(this);
form2.Show();
}
}
Form2 code behind
public partial class Form2 : Form
{
private Form1 _form1;
public Form2(Form1 form1)
{
_form1 = form1;
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
_form1.label1.Text = "lets change the text";
}
}
We are passing Form1 completely in the constructor, this could easily be the label1 control alone.
Result
I think you only need to trigger a redraw on forms 1 and 2.
after you set the text of the label, try calling labelControl.Refresh()
Or you could call refresh on form1 and form2 if that's any easier (that is a bit heavy handed though)
This will instruct the forms to redraw their visual representation based on how the data is set in the form currently.
Update:
You will need to invert your logic somewhat..
Rather than having a reverence to form 3 from form 1 and form 2, you will need to have a reference to form 1 and 2 from form3.. (woah so many form)
So then your button click method would look like this
public void button1_Click(object sender, EventArgs e)
{
form1.label1.Text = textBox3.Text;
form2.label1.Text = textBox3.Text;
form1.label1.Refresh();
form2.label1.Refresh();
}
I have a C# form called Form1.cs. By pressing a button, a new Form called Form2.cs comes up and I do something in form2. I have some variables in both forms.
I want to communicate between these two forms like this.
in form1:
string s=frm2.textbox1.text;`
form2:
if(frm1.checkbox1.checked==true)
or something like these codes.
I have tried the below code:
form1:
Form2 f=new Form2(this);
f.showDialog();`
form2:
private Form1 mainForm = null;
public Form2(Form callingForm)
{
mainForm = callingForm as Form1;
InitializeComponent();
}
`
and this works. But I don't want to use pointers like "this" and call this.mainform. Is there another way to communicate between forms like function calls?
Thank you.
Here are a couple of different approaches you can take that remove the need for Form 2 to know about Form 1 and that will make Form 2 reusable:
Delegates
You can declare a delegate function on the second form, and then pass a delegate method from the first form to the second one, so the second form can call back to the first one.
That approach means your second form no longer has any direct knowledge of your first form. It also means you can reuse the second form from any form and just pass in a delegate with the correct signature. Example below:
Form1:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 f=new Form2(UpdateTextBox);
f.ShowDialog();
}
private void UpdateTextBox(string newText)
{
label1.Text = newText;
}
}
Form 2:
public partial class Form2 : Form
{
public delegate void ChoiceMadeOnForm2Delegate(string choice);
private ChoiceMadeOnForm2Delegate _choiceDelegate;
public Form2(ChoiceMadeOnForm2Delegate choiceDelegate)
{
InitializeComponent();
_choiceDelegate = choiceDelegate;
}
private void saveButton_Click(object sender, EventArgs e)
{
_choiceDelegate(textBox1.Text);
Close();
}
}
In this example the delegate method just has one parameter, but if you want to pass back a series of values to Form 1 your delegate method declaration could include more parameters, or the parameter could be a class instead.
If you also want to set initial values for Form2 from Form 1 you can of course add those as constructor parameters for Form 2 and pass them in when you new up Form 2.
In your example Form 2 is shown as a dialog, but if you ever want to not show Form 2 modally you could even have a delegate on Form 1 that you pass to Form 2, so the forms can then communicate in two directions.
Use data binding and a shared class
Another approach is to use databinding, whereby you bind both forms to the same object and pass that object from Form 1 to Form 2 in its constructor when you open Form 2. When either form then changes the object those changes will then be reflected on both forms simultaneously and instantly.
To do that you need to read up on a concept called databinding and implement the INotifyPropertyChanged interface on the data class. You then bind the relevant controls on both forms to that class. Documentation on INotifyPropertyChanged can be found here
You can pass only information that Form2 needs and expose only information that Form1 needs
Form1
string valueOfForm2 = null;
using Form2 f = new Form2(this.checkbox1.Checked)
{
f.ShowDialog();
valueOfForm2 = f.ReturnValue;
}
Then use valueOfForm2 for you needs in the Form1
Form2
bool _IsForm1ValueChecked;
//By this property text will be exposed to outside of Form
public string ReturnValue { get { return this.textbox1.Text;} }
public Form2(bool isForm1ValueChecked)
{
_IsForm1ValueChecked = isForm1ValueChecked;
}
_IsForm1ValueChecked will be set in the contructor - then use it for your purpose in the Form2
I think for such stuff, I was using properties.
I prefer not access from one form the controls of the other one.
If I need information from one form, I prefer giving the access to this other form through properties.
More than that, you can define an interface that will contain all the properties/methods that you need for the communication between the forms. It will be clearer to work with an interface, you will get the information you need and won't be overloaded with other irrelevant information.
For example:
Interface IForm2
{
// your properties
string PersonName {get;} // Just an example
// your methods
}
class Form1: Form
{
private IForm2 _form2;
void Foo()
{
var pname = _form2.PersonName; // Just an example
}
}
class Form2: Form, IForm2
{
string PersonName
{
get
{
return personNameTextBox.Text;
}
}
}
In my main form (form1) I have checkboxes that when checked should also check the corresponding box in form2. I also want if checkboxes in form2 are checked they check the corresponding boxes on form1. The problem that I believe I am encountering is that form1 can make an object of form2 to reference, however if I instantiate an object of form1 within form2 I believe it creates an infinite loop? Any help figuring this out is appreciated.
Form1 creates an object of form2:
Form2 formSettings = new Form2();
Now when I have an event I can update form2:
public void logScanResultsToolStripMenuItem_Click(object sender, EventArgs e)
{
if (logScanResultsToolStripMenuItem.Checked)
{
formSettings.chbxLogScanResults.Checked = true;
}
else
{
formSettings.chbxLogScanResults.Checked = false;
}
}
But if I try to do something similar in Form2:
Form1 form1 = new Form1();
So that I can reference form1's menu item from within form2(formSettings) I end up creating an object (form1) that calls to make an object of Form1, which within Form1 includes a call to create an object of Form2 and thus an endless loop.
You shouldn't create an instance every time a checkbox is checked off. You need to maintain the instances alive and hide/show them as needed. Also, the constructor of one of the forms should receive the other one as parameter in its constructor so they can reference each other.
Hopefully this is clear enough. It isn't a straight out answer as you really dont have much detail in your question.
Basically you have two forms, Form1 and Form2, which will be throwing events (OnChangeEvent?) on the change of some checkboxes.
Form1 listens for events from Form2 and Form2 does the same from Form1.
If Form1's event listen receives a OnChangeEvent and changes its checkbox then it should raise an OnChangeEvent. If on the other hand it doesn't change its checkbox (as it already has the correct value) then it should not raise an OnChangeEvent.
In the body of Form1 you need to declare Form2 to hold an instance of it for referencing and to open it. When you call the Form2.Show method from Form1, you will pass a reference of itself to Form2 which you then can use to gain access back to Form1.
public partial class Form1 : Form
{
Form2 form2 = new Form2();
public Form1()
{
InitializeComponent();
}
private void form1Button_Click(object sender, EventArgs e)
{
form2.Show(this);
}
private void form1CheckBox_CheckedChanged(object sender, EventArgs e)
{
form2.ChangeCheck(form1CheckBox.Checked);
}
public void ChangeCheck(bool isItChecked)
{
form1CheckBox.Checked = isItChecked;
}
}
In Form2 you can now reference Form1 as the owner.
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void form2CheckBox_CheckedChanged(object sender, EventArgs e)
{
((Form1)this.Owner).ChangeCheck(form2CheckBox.Checked);
}
public void ChangeCheck(bool isItChecked)
{
form2CheckBox.Checked = isItChecked;
}
}