I have a timer running on form 1 with a label called "timenumber" showing the time, i also have a second form that has a label "timer". How do i link these in a way that they both so the same value at the same time. Form 1 is used as a controller and the form 2 is the one that is displayed in another monitor.
Option 1
Pass a reference to the Count Down Label in Form1 to Form2 using its constructor, then use this reference to subscribe to the Label's TextChanged event:
In Form1:
private int CountDown = 100;
private void button1_Click(object sender, EventArgs e)
{
Form2 form2 = new Form2(this.[The Counter Label]);
form2.Show();
this.timer1.Enabled = true;
}
private void timer1_Tick(object sender, EventArgs e)
{
this.[The Counter Label].Text = CountDown.ToString();
if (CountDown == 0)
this.timer1.Enabled = false;
CountDown -= 1;
}
In Form2:
public form2() : this(null) { }
public form2(Control timerCtl)
{
InitializeComponent();
if (timerCtl != null) {
timerCtl.TextChanged += (s, evt) => { this.[Some Label].Text = timerCtl.Text; };
}
}
Option 2
Use a Public Property of Form2 that can be set to a Control reference. Set this property in Form1 right after a new instance of Form2 has beed created.
This, however, implies that Form1 needs to know about this property in Form2:
In Form1:
private int CountDown = 100;
private void button1_Click(object sender, EventArgs e)
{
Form2 form2 = new Form2();
form2.Show();
form2.CountDownControl = this.[The Counter Label];
this.timer1.Enabled = true;
}
private void timer1_Tick(object sender, EventArgs e)
{
this.[The Counter Label].Text = CountDown.ToString();
if (CountDown == 0)
this.timer1.Enabled = false;
CountDown -= 1;
}
In Form2:
private Control timerCtl = null;
public Control CountDownControl {
set { this.timerCtl = value;
if (value != null) {
this.timerCtl.TextChanged += (s, evt) => { this.[Some Label].Text = timerCtl.Text; };
}
}
}
Many other options exist.
You could also use a Public Property in Form2 and set this property directly from the Timer.Tick event. The public property, as in the second example, could set the Text property of one of its controls to the value of the property.
I don't like this option very much, nonetheless it's available.
In Form1:
private int CountDown = 100;
private void button1_Click(object sender, EventArgs e)
{
Form2 form2 = new Form2();
form2.Show();
this.timer1.Enabled = true;
}
private void timer1_Tick(object sender, EventArgs e)
{
this.[The Counter Label].Text = CountDown.ToString();
form2?.CountDownValue = CountDown;
if (CountDown == 0)
this.timer1.Enabled = false;
CountDown -= 1;
}
In Form2:
public int CountDownValue {
set { this.[Some Label].Text = value.ToString(); }
}
}
You could also have a custom event in Form1 that Form2 could subscribe, or implement INotifyPropertyChange. But this is, give or take, the same thing as Option1.
If form1 opens form2, this is easy. In Form2, define a property to set the text on the label:
public string TimerText
{
set => _timerLabel.Text = value;
}
You might also need to call _timerLabel.Invalidate(); to force the label to refresh.
Then, when the countdown timer in form1 updates, simply set that property in form2:
private void Timer_Tick(object sender, EventArgs e)
{
// calculate remaining time
_form2.TimerText = remainingTime.ToString();
}
Here, _form2 is a reference to the Form2 object that form1 is showing.
You could have the property in Form2 be an int or double rather than a string; which you choose may depend on whether you do anything else with the value in Form2.
Related
I am very new to C# so I am sorry if I use wrong terms. Here is my problem. I have 2 forms. and I want If I click the button in Form1, it shows up the Form2 by overlapping the Form1. And now, if I click the button in form2, I want the form1 overlap the form2. But I always get error "stackOverFlowException". Why did i get the error? How to resolve it? I am sorry if my question is not clear. I hope these picture can explain better about my question.
Here is the code for form1.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Form2 frm2 = new Form2();
private void Form1_Load(object sender, EventArgs e)
{
frm2.Show();
}
private void button1_Click(object sender, EventArgs e)
{
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
frm2.Left += 10;
if (frm2.Left >= 750)
{
timer1.Stop();
this.TopMost = false;
frm2.TopMost = true;
timer2.Start();
}
}
private void timer2_Tick(object sender, EventArgs e)
{
frm2.Left -= 10;
if (frm2.Left <= 535)
{
timer2.Stop();
}
}
}
}
and here is the code for form2
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
Form1 frm1 = new Form1();
private void Form2_Load(object sender, EventArgs e)
{
frm1.Show();
}
private void button1_Click(object sender, EventArgs e)
{
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
frm1.Left += 10;
if (frm1.Left >= 750)
{
timer1.Stop();
this.TopMost = false;
frm1.TopMost = true;
timer2.Start();
}
}
private void timer2_Tick(object sender, EventArgs e)
{
frm1.Left -= 10;
if (frm1.Left <= 535)
{
timer2.Stop();
}
You are creating and endless chain of opened forms.
When you first create a Form1 object with new Form1(), the initialization code inside this form
Form2 frm2 = new Form2();
... is called. This in turn triggers the initialization code of Form2, which is
Form1 frm1 = new Form1();
This creates a new instance of this form (now you have two Form1 instances) and calls Form2 frm2 = new Form2(); again in this new instance (now you have two Form2 instances). This goes on until thousands of form objects have been created and the stack overflows.
What can you do about it?
In Form2 add a parameter to the constructor that allows you to pass a reference to the first form
private readonly Form1 _frm1;
public Form2 (Form1 frm1)
{
InitializeComponent();
_frm1 = frm1;
}
In Form1 do this
private Form2 _frm2;
private void Form1_Load(object sender, EventArgs e)
(
_frm2 = new Form2(this);
)
I.e. Form2 never creates a Form1. Instead, it gets a reference to the already opened form.
How do you bring a form to front?
The TopMost property controls the behavior of a form when it is opened. Instead, use
_frm1.BringToFront();
to change the z-order afterwards.
I have a timer function within my main app which acts as a timed session. However, I want to change the timer interval and an ability to turn it on and off via the sub form, but cannot use the timer functions elements within another form to change the settings. Below is my code snippet. Any tips or example will be appreciated.
Attempt :
Main Form
private void Booyaa_Load(object sender, EventArgs e)
{
BooyaaTimer.Interval = 45 * 60 * 1000); // 45 mins
BooyaaTimer.Tick += new EventHandler(BooyaaTimer_Tick);
BooyaaTimer.Start();
if (!Properties.Settings.Default.SettingShutdown)
{
MessageBox.Show("Not properly shut down");
GetPass pass = new GetPass();
DialogResult result = pass.ShowDialog();
if (result == DialogResult.OK) {
Properties.Settings.Default.SettingShutdown = true;
Properties.Settings.Default.Save();
}
else
{
Close();
}
}
private void BooyaaTimer_Tick(object sender, EventArgs e)
{
MessageBox.Show("TIME IS UP");
GetPass pass = new GetPass();
DialogResult result = pass.ShowDialog();
if (result == DialogResult.OK)
{
Show();
Properties.Settings.Default.SettingShutdown = true;
Properties.Settings.Default.Save();
}
else
{
BooyaaTimer.Start();
Properties.Settings.Default.SettingShutdown = false;
Properties.Settings.Default.Save();
Hide();
}
}
Timer controls form
public object BooyaaTimer { get; private set; }
private void btn_confirm_Click(object sender, EventArgs e)
{
BooyaaTimer.Interval = Int32.Parse(textBox1.Text); // gives error on interval
}
I'm going to make a guess. The Timer is created in the main form
public partial class Form1 : Form {
Timer BooyaaTimer = new Timer(); // Or this is created in Designer
void SomeFunctionThatCreatesTheOtherForm() {
TimerControlsForm form2 = new TimerControlsForm();
// Pass the timer to form2
form2.BooyaTimer = BooyaTimer;
form2.ShowDialog();
}
}
And the other form
public partial class TimerControlsForm : Form {
// This has to be a Timer object
public Timer BooyaTimer {get; set;}
private void btn_confirm_Click(object sender, EventArgs e) {
BooyaaTimer.Interval = Int32.Parse(textBox1.Text);
}
}
This question already has answers here:
Communicate between two windows forms in C#
(12 answers)
Closed 1 year ago.
I wanna know how I can send variables from Form2 to Form1. I have one textbox and button in Form1 and one textbox and button in Form2. My application starts at Form1, textbox1 is empty and by clicking button Form2 will appear. In Form2 I want to write number and by clicking on the button send it to Form1 textbox.
I was trying this code, but I dont know how to solve it.
Form1 code:
public static int number;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 form = new Form2();
form.Show();
}
Form2 code
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form1.number = textBox1.Text;
this.Visible = false;
}
Now I have variable called number in Form1, which contains value of Form2 Textbox, right? But how do I say: textbox1.text(Form1) = number after that action? Do I need refresh Form1 somehow?
Thanks!
I'd say a nice easy way to do this kind of thing, is via making a public event:
In form two, add an event:
public partial Class Form2
{
public event Action<string> SomethingHappened;
...
We need to fire the event on Form2 - to notify subscribers:
//On Form2
private void button1_Click(object sender, EventArgs e)
{
if(SomethingHappened != null)
SomethingHappened (textBox1.Text);
}
Then, upon creation 'subscribe' the parent form Form1 to action on the sub-form:
Form2 form = new Form2();
//Here, we assign an event handler
form.SomethingHappened += (string valueFromForm2) =>
{
//Event handled on Form1
this.Number = valueFromForm2;
};
The setup sounds kinda like a settings dialog where you can't continue in Form1 until Form2 is closed.
If this is the case, then something more like his would be appropriate in Form1:
public partial class Form1 : Form
{
private int number = 411;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.textBox1.Enabled = false;
this.textBox1.Text = number.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 f2 = new Form2(this.number);
if (f2.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
this.number = f2.Number;
this.textBox1.Text = this.number.ToString();
}
}
}
With Form2 looking something like:
public partial class Form2 : Form
{
public Form2(int number)
{
InitializeComponent();
this.textBox1.Text = number.ToString();
}
private int number = 0;
public int Number
{
get { return this.number; }
}
private void btnOK_Click(object sender, EventArgs e)
{
int value;
if (int.TryParse(this.textBox1.Text, out value))
{
this.number = value;
this.DialogResult = System.Windows.Forms.DialogResult.OK;
}
else
{
MessageBox.Show(textBox1.Text, "Invalid Integer");
}
}
}
I have two Forms:
Form1
Form2
Whenever I check/uncheck a CheckBox checkBox1 on Form2 I want to update textbox1.Readonly that is on Form1. If both textbox1 and checkbox1 had been on the same Form it would be easy go:
private void checkBox1_CheckedChanged(object sender, EventArgs e) {
textbox1.Readonly = checkBox1.Checked;
}
What shall I do in my case when textbox1 and checkbox1 are on different Forms?
You can put it like this:
public partial class Form1: Form {
...
// textBox1 is private (we can't access in from Form2)
// so we'd rather create a public property
// in order to have an access to textBox1.Readonly
public Boolean IsLocked {
get {
return textBox1.Readonly;
}
set {
textBox1.Readonly = value;
}
}
}
...
public partial class Form2: Form {
...
private void checkBox1_CheckedChanged(object sender, EventArgs e) {
// When checkBox1 checked state changed,
// let's find out all Form1 instances and update their IsLocked state
foreach (Form fm in Application.OpenForms) {
Form1 f = fm as Form1;
if (!Object.RefrenceEquals(f, null))
f.IsLocked = checkBox1.Checked;
}
}
}
You should use events and delegates.
On Form2, We're create a delegate and event
public delegate void OnCheckedEventHandler(bool checkState);
public event OnCheckedEventHandler onCheckboxChecked;
public void checkBox1_Checked(object sender, EventArgs e)
{
if (onCheckboxChecked != null)
onCheckboxChecked(checkBox1.Checked);
}
And on Form1, we're realize this event:
void showForm2()
{
Form2 f2 = new Form2();
f2.onCheckboxChecked += onCheckboxChecked;
f2.Show();
}
public void onCheckboxChecked(bool checkState)
{
textBox1.ReadOnly = checkState;
}
For simplier and more flexible
Form1:
public class Form1 : System.Windows.Forms.Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 tmpFrm = new Form2();
tmpFrm.txtboxToSetReadOnly = this.txtMyTextBox; //send the reference of the textbox you want to update
tmpFrm.ShowDialog(); // tmpFrm.Show();
}
}
FOrm2:
public class Form2 : System.Windows.Forms.Form
{
public Form2()
{
InitializeComponent();
}
TextBox _txtboxToSetReadOnly = null;
public TextBox txtboxToSetReadOnly
{
set{ this._txtboxToSetReadOnly = value; }
get {return this._txtboxToSetReadOnly;}
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
if( this._txtboxToSetReadOnly != null) this._txtboxToSetReadOnly.ReadOnly = checkbox1.Checked;
/*
or the otherway
if( this._txtboxToSetReadOnly != null) this._txtboxToSetReadOnly.ReadOnly = !checkbox1.Checked;
*/
}
}
OK i wish to make it so there is a limit to how much a button can be clicked because with multiple boxes open causes my application to crash ~:(
here is my code for the form that i wish to stop it from opening to many don't get me wrong i do want multiple boxes just not many:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
this.KeyPreview = true;
this.KeyDown += new KeyEventHandler(Form1_KeyDown);
}
private void pictureBox1_Click(object sender, EventArgs e)
{
var myForm = new Form2();
myForm.Show();
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Alt && e.KeyCode == Keys.A)
{
Form3 f3 = new Form3();
f3.ShowDialog();
}
}
private void Form2_Load(object sender, EventArgs e)
{
}
}
}
Use a private counter. Every time a user clicks the button, increment the counter, and check the counter before showing the new form.
private int clickCounter = 0;
private void pictureBox1_Click(object sender, EventArgs e)
{
this.clickCounter++;
if (this.clickCounter < 10) // arbitrary number
{
var myForm = new Form2();
myForm.Show();
}
}
This will work for ensuring the user doesn't abuse the button on a single instance of the form. To make sure the same counter applies to all instances of the form, make it static:
private static int clickCounter = 0;
private void pictureBox1_Click(object sender, EventArgs e)
{
clickCounter++;
if (clickCounter < 10) // arbitrary number
{
var myForm = new Form2();
myForm.Show();
}
}
If you'd like to decrement the counter when a form closes as Junior Programmer suggests, you can bind to the Closing event. This will effectively limit the number of new forms that can be opened (rather just limiting the number of times the button can be clicked). This will work for both the local and static counter versions:
myForm_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
clickCounter--;
}
private void pictureBox1_Click(object sender, EventArgs e)
{
if (clickCounter < 10) // arbitrary number
{
clickCounter++;
var myForm = new Form2();
myForm.Closing += myForm_Closing;
myForm.Show();
}
}
This is another solution which doesn't differ much from the p.s.w.g's answer;
public class Form1 : Form {
private static int count = 0;
public Form1(){
InitializeComponent();
button1.Click += click;
}
private void click(object sender, EventArgs e){
count++;
if(count > 20) {
button1.Click -= click;
count = 0;//If you want to reset
}
}
}
Simply create a global static int count variable and set it to 0. Every time the button is clicked, increase the value of count (count++).
So when the button is clicked put all your event handling in the bellow if statement instead of my comment
if(count<5)
{
count++;
//run your code for the button event
}
else
{
MessageBox.Show("You have pressed the button too many times");
}
So using your above code, your final should look like this
public partial class Form2 : Form
{
public static int count=0;
public Form2()
{
InitializeComponent();
this.KeyPreview = true;
this.KeyDown += new KeyEventHandler(Form1_KeyDown);
}
private void pictureBox1_Click(object sender, EventArgs e)
{
if(count<5)
{
count++;
var myForm = new Form2();
myForm.Show();
}
else
{
MessageBox.Show("You have pressed the button too many times");
}
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Alt && e.KeyCode == Keys.A)
{
Form3 f3 = new Form3();
f3.ShowDialog();
}
}
private void Form2_Load(object sender, EventArgs e)
{
}
}