C# Specific value passing between forms without new instance - c#

I have a C# application that allows the user to log certain events that occur in a game. For simplicity I'll call them ParentForm and ChildForm.
ParentForm is used 99% of the time, to log common events. This is represented as the user clicking a PictureBox and the Tag property of that PictureBox being added to a ListBox. When a "rare" event occurs, the user can click a "log rare event" button on ParentForm to open ChildForm which opens a set of "rare event" PictureBoxes, which function the same as in the ParentForm. The challenge is that I want these common and rare events to be logged to the same ListBox, so I am trying to find out how I would get a PictureBox click (and subsequent Tag from this PictureBox) on the ChildForm to the ListBox on the ParentForm.
The ParentForm does not close while ChildForm is open, and needs to stay open.
In the ParentForm code, I already have the code needed to capture one of the PictureBox clicks and grabbing the Tag, as well as handling dealing with adding it to the ListBox, so it'd be nice if I could just use these.
Here's what I've tried so far for the Parent:
// This file is EventLogger.cs
using rareEvent;
namespace mainWindow {
public partial class EventLogger : Form {
// In the ParentForm (listeners for PictureBox clicks are handled elsewhere)
public void pictureBox_Click(object sender, EventArgs e) {
PictureBox pbSender = (PictureBox) sender;
// Open new window and handle "rare" drops
if (pbSender.Tag.ToString() == "rare") {
// Open rare form
EventLogger.RareForm rare = new EventLogger.RareForm();
rare.Show();
}
}
}
}
and here's the child:
// This file is Rare.cs
using EventLogger;
namespace rareEvent {
public partial class rareEventForm : Form {
// In the ChildForm
private void pictureBox_Click(object sender, EventArgs e) {
// Does not compile if form is not instantiated, but I do not
// want a new instance
EventLogger form;
form.pictureBox_Click(sender, e);
}
}
}
I figured something like this would work, but it gives the error
The type or namespace name 'EventLogger' does not exist in the namespace
'mainWindow' (are you missing an assembly reference?)
Any help would be much appreciated. All the other examples I've found of value passing between forms all seem to create new instances which I don't want or were 8 years old and didn't work.
Appreciate it!
Edit: Code updated to have using <namespace> in each file. The problem still exists of not being able to send values between both forms without using new. (See comment to this answer)

In the first form create an instance (of it) here like my form1. It must be static and all datatypes you want to access should be public.
//FORM1
public partial class Form1 : Form
{
//Instance of this form
public static Form1 instance;
//For testing
public string myProperty = "TEST";
//Assign instance to this either in the constructor on on load like this
public Form1()
{
InitializeComponent();
instance = this;
}
//or
private void Form1_Load(object sender, EventArgs e)
{
//Assign the instance to this class
instance = this;
}
Then in form2 when calling EventLogger.RareForm rare = new EventLogger.RareForm(); instead of new form do
EventLogger.RareForm rare = EventLogger.RareForm.instance
Or in my case
Form1 frm = Form1.instance;
I then check the property of form 1 FROM form2 like so
Console.WriteLine(frm.myProperty);
Output was "Test"
Any trouble shout.

Related

C# How do I handle a one time startup condition for a form if the form is generated new each time?

I have form A, which opens form B after an event then hides itself. Form B generates conditions for form A then returns to form A and closes itself; however, due to conflict with code, I will have to generate form A anew lest I encounter a stackoverflow exception / my application not closing properly (due to form A, the main form, being hidden)
This has gotten a bit confusing, essentially I've already solved this by declaring the main form as new each time, however, I wish to be able to handle first time startup events like those tutorial messages for certain applications. Without the overhead of having to create a log to store my boolean, how will I detect if it's the first time the form is opened?
Normally I would:
Event(){
bool startup;
if (startup = true) {
startup = false;
return;
}
//Rest of code
}
However, since the form is generated new each time, this will always remain true.
Here's the code:
Form A variables:
Account AccountForm = new Account();
Button event:
AccountForm.QR = this;
this.Hide();
AccountForm.ShowDialog();
Form B:
public Form QR { get; set; }
Button event:
QR = new QueryRefiner();
this.QR.Show();
this.Close();
This is all of it I think. I take the new declaration out of QR, and I would receive a StackOverflow exception. I guess I should have created a new question for this, but there it is. (I think i'm on the timer still)
Well,an easy solution is to make a new constructor in your FormA to get a parameter indicating that it is created from FormB, something like:
public FormA(bool byFormB)
{
if (byFormB)
{
//do what you have to do when it's created from FormB
}
}
And just create it like this from FormB: FormA frm=new FormA(true);
Anyway, I would not create a new FormA each time, just hide/show it.
Here's one way to do it: Expose a public property in your FormB that holds a reference to a FormA. When you create an instance of FormB from FormA, set the reference to point to FormA. Then, in the Form_Closing() event of FormB, show the FormA.
You can also expose public properties and/or methods on your FormA so that FormB can pass on any information it gathered back to FormA before it exits:
public partial class FormB : Form
{
public FormA formToShowOnClose { get; set; }
private void FormB_FormClosing(object sender, FormClosingEventArgs e)
{
if (formToShowOnClose != null)
{
formToShowOnClose.TableName = txtTableName.txt;
formToShowOnClose.LoadData();
formToShowOnClose.Show();
}
}
// Other form B code here...
}
public partial class FormA : Form
{
public string TableName { get; set; }
public void LoadData()
{
// Do something with TableName here
}
private void button1_Click(object sender, EventArgs e)
{
var formB = new FormB();
formB.formToShowOnClose = this;
this.Hide();
formB.Show();
}
// Other form A code here...
}

C# - Making a GroupBox visible in main form after the prompt form condition is satisfied [duplicate]

I have two forms, one is the main form and the other is an options form. So say for example that the user clicks on my menu on the main form: Tools -> Options, this would cause my options form to be shown.
My question is how can I send data from my options form back to my main form? I know I could use properties, but I have a lot of options and this seems like an tedious odd thing to do.
So what is the best way?
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;
}
}
(source: ruchitsurati.net)
(source: ruchitsurati.net)
In the comments to the accepted answer, Neeraj Gulia writes:
This leads to tight coupling of the forms Form1 and Form2, I guess instead one should use custom events for such kind of scenarios.
The comment is exactly right. The accepted answer is not bad; for simple programs, and especially for people just learning programming and trying to get basic scenarios to work, it's a very useful example of how a pair of forms can interact.
However, it's true that the coupling that example causes can and should be avoided, and that in the particular example, an event would accomplish the same thing in a general-purpose, decoupled way.
Here's an example, using the accepted answer's code as the baseline:
Form1.cs:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 frm = new Form2();
frm.Button1Click += (s1, e1) => Lbl.Text = ((Form2)s1).Message;
frm.Show();
}
}
The above code creates a new instance of Form2, and then before showing it, adds an event handler to that form's Button1Click event.
Note that the expression (s1, e1) => Lbl.Text = ((Form2)s1).Message is converted automatically by the compiler to a method that looks something similar to (but definitely not exactly like) this:
private void frm_Message(object s1, EventArgs e1)
{
Lbl.Text = ((Form2)s1).Message;
}
There are actually lots of ways/syntaxes to implement and subscribe the event handler. For example, using an anonymous method as the above, you don't really need to cast the sender parameter; instead you can just use the frm local variable directly: (s1, e1) => Lbl.Text = frm.Message.
Going the other way, you don't need to use an anonymous method. You could in fact just declare a regular method just like the compiler-generated one I show above, and then subscribe that method to the event: frm.Button1Click += frm_Message; (where you have of course used the name frm_Message for the method, just as in my example above).
Regardless of how you do it, of course you will need for Form2 to actually implement that Button1Click event. That's very simpleā€¦
Form2.cs:
public partial class Form2 : Form
{
public event EventHandler Button1Click;
public string Message { get { return txtMessage.Text; } }
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
EventHandler handler = Button1Click;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
In addition to the event, I've also declared a property Message that exposes the Text property (and only the Text property, and only as read-only in fact) of the txtMessage control. This allows the subscriber to the event to get the value and do whatever it needs to with it.
Note that all that the event does is to alert the subscriber that the button has in fact been clicked. It's up to the subscriber to decide how to interpret or react to that event (e.g. by retrieving the value of the Message property and assigning it to something).
Alternatively, you could in fact deliver the text along with the event itself, by declaring a new EventArgs sub-class and using that for the event instead:
public class MessageEventArgs : EventArgs
{
public string Message { get; private set; }
public MessageEventArgs(string message)
{
Message = message;
}
}
public partial class Form2 : Form
{
public event EventHandler<MessageEventArgs> Button1Click;
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
EventHandler handler = Button1Click;
if (handler != null)
{
handler(this, new MessageEventArgs(txtMessage.Text));
}
}
}
Then the subscriber can just retrieve the message value directly from the event object:
frm.Button1Click += (sender, e) => Lbl.Text = e.Message;
The important thing note in all of the above variations is that at no point does the class Form2 need to know anything about Form1. Having Form1 know about Form2 is unavoidable; after all, that's the object that will create a new Form2 instance and use it. But the relationship can be asymmetrical, with Form2 being usable by any object that needs the features it offers. By exposing the functionality as an event (and optionally with a property), it makes itself useful without limiting its usefulness to only the Form1 class.
The best in this case would be to have some OptionsService class/interface that is accessible via IServiceProvider.
Just add an event when something changes, and the rest of the app can respond to it.
There are lots of ways to perform communication between two Forms.
Some of them have already been explained to you. I am showing you the other way around.
Assuming you have to update some settings from the child form to the parent form. You can make use of these two ways as well :
Using System.Action (Here you simply pass the main forms function as the parameter to the child form like a callback function)
OpenForms Method ( You directly call one of your open forms)
Using System.Action
You can think of it as a callback function passed to the child form.
// -------- IN THE MAIN FORM --------
// CALLING THE CHILD FORM IN YOUR CODE LOOKS LIKE THIS
Options frmOptions = new Options(UpdateSettings);
frmOptions.Show();
// YOUR FUNCTION IN THE MAIN FORM TO BE EXECUTED
public void UpdateSettings(string data)
{
// DO YOUR STUFF HERE
}
// -------- IN THE CHILD FORM --------
Action<string> UpdateSettings = null;
// IN THE CHILD FORMS CONSTRUCTOR
public Options(Action<string> UpdateSettings)
{
InitializeComponent();
this.UpdateSettings = UpdateSettings;
}
private void btnUpdate_Click(object sender, EventArgs e)
{
// CALLING THE CALLBACK FUNCTION
if (UpdateSettings != null)
UpdateSettings("some data");
}
OpenForms Method
This method is easy (2 lines). But only works with forms that are open.
All you need to do is add these two lines where ever you want to pass some data.
Main frmMain = (Main)Application.OpenForms["Main"];
frmMain.UpdateSettings("Some data");
Properties is one option, shared static class - another option, events - another option...
You might try AutoMapper. Keep your options in a separate class and then use AutoMapper to shuttle the data between the class and the form.
Create a Class and put all your properties inside the class .. Create a Property in the parent class and set it from your child (options) form
You can have a function in Form B like so:
public SettingsResults GetNewSettings()
{
if(this.ShowDialog() == DialogResult.Ok)
{
return new SettingsResult { ... };
}
else
{
return null;
}
}
And you can call it like this:
...
using(var fb = new FormB())
{
var s = fb.GetNewSettings();
...
// Notify other parts of the application that settings have changed.
}
MVC, MVP, MVVM -- slight overkill for someone admittedly saying they want tutorials. Those are theories that have entire courses dedicated to them.
As already posted, passing an object around is probably easiest. If treating a class as an object (interchangeable in this sense) is new, then you may want to spend another 2-4 weeks figuring out properties and constructors and such.
I'm not a C# master by any means, but these concepts need to be pretty concrete if you want to go much further beyond passing values between two forms (also classes/objects in their own right). Not trying to be mean here at all, it just sounds like you're moving from something like VB6 (or any language with globals) to something far more structured.
Eventually, it will click.
This is probably sidestepping your problem a little bit, but my settings dialog uses the Application Settings construct. http://msdn.microsoft.com/en-us/library/k4s6c3a0.aspx
I can't find a good example that's similar to how I do it (which is actually having an actual class+object), but this covers another way of doing it:
Reading default application settings in C#
A form is a class, just like any other class. Add some public variables to your form class and set them when they click the button to close the form (technically they are just hiding it).
A VB.NET example, but you'll get the idea -
In your OptionsForm class:
Public Option1 as String = ""
etc. Set them when they hit the "Ok" button.
So in your main form, when they hit the "options" button - you create your options form:
OptionsForm.ShowDialog()
when it exits, you harvest your option settings from the public variables on the form:
option1 = OptionsForm.Option1
etc.
The best way to deal with communication between containers is to implement an observer class
The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.
(Wikipedia)
the way i do this is creating an Observer class, and inside it write something like this:
1 public delegate void dlFuncToBeImplemented(string signal);
2 public static event dlFuncToBeImplemented OnFuncToBeImplemented;
3 public static void FuncToBeImplemented(string signal)
4 {
5 OnFuncToBeImplemented(signal);
6 }
so basically: the first line says that there would be a function that somebody else will implement
the second line is creating an event that occurs when the delegated function will call
and the third line is the creation of the function that calls the event
so in your UserControl, you should add a function like this:
private void ObserverRegister()//will contain all observer function registration
{
Observer.OnFuncToBeImplemented += Observer_OnFuncToBeImplemented;
/*and more observer function registration............*/
}
void Observer_OnFuncToBeImplemented(string signal)//the function that will occur when FuncToBeImplemented(signal) will call
{
MessageBox.Show("Signal "+signal+" received!", "Atention!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
and in your Form you should do something like:
public static int signal = 0;
public void button1_Click(object sender, EventArgs e)
{
Observer.FuncToBeImplemented(signal);//will call the event in the user control
}
and now, you can register this function to a whole bunch of other controls and containers and they will all get the signal
I hope this would help :)

Calling a method from another Form in C#

I want that when I insert or update records in another form (Form2), the DataGridView on Form1 should automatically refresh (call btnRefresh) after each operation or preferably wait until all change operations have finished, and update the DataGridView form Form2's closing event with all changes.
I believe in VB.NET this is achieved with Form1.DataGridView.Refresh, but I am not sure in C#. I was told that I pass the reference of the DataGridView on Form1 to Form2 using properties but since I'm new to C#, I didn't know how to. How can I resolve this issue?
My refresh button code:
private void btnRefresh_Click(object sender, EventArgs e)
{
GVThesis.DataSource = thesisRepository.GetThesis();
GVThesis.Refresh();
}
Firs, wrap your refresh code into a method of its own, and call that from your click event handler method, like so:
private void btnRefresh_Click(object sender, EventArgs e)
{
this.RefreshData();
}
public void RefreshData()
{
GVThesis.DataSource = thesisRepository.GetThesis();
GVThesis.Refresh();
}
Then, asuming you are instantiating and launching the new form (Form2) from your Form1, simply go into the code of Form2 and create yourself a new constructor overload which will accept a reference to Form1, and store it in a private variable, like so:
public partial class Form2 : Form
{
private Form1 frm1;
public Form2()
{
InitializeComponent();
}
public Form2(Form1 otherForm)
{
InitializeComponent();
this.frm1 = otherForm;
}
}
Then you can call the "refresh" from anywhere you like in Form2 like so:
this.frm1.RefreshData();
EDIT:I created a small sample, I cannot upload it here...but here is a screenshot of both the program itself in VS, as well as a screenshot of the result of running it and performing the function...hopefully that will help.
The program (zoom your view if it appears too small)
The Result:

Firing a method in form 1 on click of a button on form2

I am quite new to windows forms. I would like to know if it is possible to fire a method in form 1 on click of a button in form 2?
My form 1 has a combobox. My form 2 has a Save button. What I would like to achieve is:
When the user clicks on Save in form 2, I need to check if form 1 is open. If it is open, I want to get the instance and call the method that would repopulate the combo on form 1.
I would really appreciate if I get some pointers on how I can do work this out. If there any other better way than this, please do let me know.
Thanks :)
Added:
Both form 1 and form 2 are independent of each other, and can be opened by the user in any order.
You can get a list of all currently open forms in your application through the Application.OpenForms property. You can loop over that list to find Form1. Note though that (in theory) there can be more than one instance of Form1 (if your application can and has created more than one instance).
Sample:
foreach (Form form in Application.OpenForms)
{
if (form.GetType() == typeof(Form1))
{
((Form1)form).Close();
}
}
This code will call YourMethod on all open instances of Form1.
(edited the code sample to be 2.0-compatible)
Of course this is possible, all you need is a reference to Form1 and a public method on that class.
My suggestion is to pass the Form1 reference in the constructor of Form2.
What you can do is create static event in another class and then get Form 1 to subscribe to the event. Then when button clicked in Form 2 then raise the event for Form 1 to pick up on.
You can have declare the event in Form 1 if you like.
public class Form1 : Form
{
public static event EventHandler MyEvent;
public Form1()
{
Form1.MyEvent += new EventHandler(MyEventMethod);
}
private void MyEventMethod(object sender, EventArgs e)
{
//do something here
}
public static void OnMyEvent(Form frm)
{
if (MyEvent != null)
MyEvent(frm, new EventArgs());
}
}
public class Form2 : Form
{
private void SaveButton(object sender, EventArgs e)
{
Form1.OnMyEvent(this);
}
}

How to change text in a textbox on another form in Visual C#?

In Visual C# when I click a button, I want to load another form. But before that form loads, I want to fill the textboxes with some text. I tried to put some commands to do this before showing the form, but I get an error saying the textbox is inaccessible due to its protection level.
How can I set the textbox in a form before I show it?
private void button2_Click(object sender, EventArgs e)
{
fixgame changeCards = new fixgame();
changeCards.p1c1val.text = "3";
changeCards.Show();
}
When you create the new form in the button click event handler, you instantiate a new form object and then call its show method.
Once you have the form object you can also call any other methods or properties that are present on that class, including a property that sets the value of the textbox.
So, the code below adds a property to the Form2 class that sets your textbox (where textbox1 is the name of your textbox). I prefer this method method over making the TextBox itself visible by modifying its access modifier because it gives you better encapsulation, ensuring you have control over how the textbox is used.
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
public string TextBoxValue
{
get { return textBox1.Text;}
set { textBox1.Text = value;}
}
}
And in the button click event of the first form you can just have code like:
private void button1_Click(object sender, EventArgs e)
{
Form2 form2 = new Form2();
form2.TextBoxValue = "SomeValue";
form2.Show();
}
You can set "Modifiers" property of TextBox control to "Public"
Try this.. :)
Form1 f1 = (Form1)Application.OpenForms["Form1"];
TextBox tb = (TextBox)f1.Controls["TextBox1"];
tb.Text = "Value";
I know this was long time ago, but seems to be a pretty popular subject with many duplicate questions. Now I had a similar situation where I had a class that was called from other classes with many separate threads and I had to update one specific form from all these other threads. So creating a delegate event handler was the answer.
The solution that worked for me:
I created an event in the class I wanted to do the update on another form. (First of course I instantiated the form (called SubAsstToolTipWindow) in the class.)
Then I used this event (ToolTipShow) to create an event handler on the form I wanted to update the label on. Worked like a charm.
I used this description to devise my own code below in the class that does the update:
public static class SubAsstToolTip
{
private static SubAsstToolTipWindow ttip = new SubAsstToolTipWindow();
public delegate void ToolTipShowEventHandler();
public static event ToolTipShowEventHandler ToolTipShow;
public static void Show()
{
// This is a static boolean that I set here but is accessible from the form.
Vars.MyToolTipIsOn = true;
if (ToolTipShow != null)
{
ToolTipShow();
}
}
public static void Hide()
{
// This is a static boolean that I set here but is accessible from the form.
Vars.MyToolTipIsOn = false;
if (ToolTipShow != null)
{
ToolTipShow();
}
}
}
Then the code in my form that was updated:
public partial class SubAsstToolTipWindow : Form
{
public SubAsstToolTipWindow()
{
InitializeComponent();
// Right after initializing create the event handler that
// traps the event in the class
SubAsstToolTip.ToolTipShow += SubAsstToolTip_ToolTipShow;
}
private void SubAsstToolTip_ToolTipShow()
{
if (Vars.MyToolTipIsOn) // This boolean is a static one that I set in the other class.
{
// Call other private method on the form or do whatever
ShowToolTip(Vars.MyToolTipText, Vars.MyToolTipX, Vars.MyToolTipY);
}
else
{
HideToolTip();
}
}
I hope this helps many of you still running into the same situation.
In the designer code-behind file simply change the declaration of the text box from the default:
private System.Windows.Forms.TextBox textBox1;
to:
protected System.Windows.Forms.TextBox textBox1;
The protected keyword is a member access modifier. A protected member is accessible from within the class in which it is declared, and from within any class derived from the class that declared this member (for more info, see this link).
I also had the same doubt, So I searched on internet and found a good way to pass variable values in between forms in C#, It is simple that I expected. It is nothing, but to assign a variable in the first Form and you can access that variable from any form. I have created a video tutorial on 'How to pass values to a form'
Go to the below link to see the Video Tutorial.
Passing Textbox Text to another form in Visual C#
private void button1_Click(object sender, EventArgs e)
{
Form2 frm = new Form2();
TextBox txt = (TextBox)frm.Controls.Find("p1c1val", true)[0];
txt.Text = "foo";
}

Categories

Resources