I have a form to ask for some data. At leaving of an input field (TextBox, DGV) the appropriate _Validating methode or _CellValueChanged methode is called.
If I want to end the program this methode is called, too - before the _FormClosing methode is called.
How can I fin out whether the program branches into the _FormClosing methode or not?
private void txb_Validating(object sender, CancelEventArgs e)
{
doLog("Text 1");
}
private void dgv_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
doLog("Text 2");
}
private void doLog(string txt)
{
// this is first called at closing...
if( [FormClosing is active] )
{
// Do something
}
else
{
// Do someting different
}
}
private void MyForm_FormClosing(object sender, FormClosingEventArgs e)
{
// ... and this but later
// Write the Logfile
}
How have I to replace [FormClosing is active] to get to the right result?
I tried so
if ( this.FormClosing== true )
and so
this.FormClosing +=new FormClosingEventHandler(MyForm_FormClosing);
and so
FormClosingEventHandler cl = new FormClosingEventHandler(MyForm_FormClosing);
but I always was in a dead end.
This would do the trick:
public class YourForm : Form
{
private bool bIsClosing = false;
public YourClass()
{
InitializeComponent();
this.FormClosing +=
new FormClosingEventHandler(MyForm_FormClosing);
}
private void txb_Validating(object sender, CancelEventArgs e)
{
doLog("Text 1");
}
private void dgv_CellValueChanged(object sender,
DataGridViewCellEventArgs e)
{
doLog("Text 2");
}
private void doLog(string txt)
{
// this is first called at closing...
if( bIsClosing )
{
// Do something
}
else
{
// Do someting different
}
}
private void MyForm_FormClosing(object sender, FormClosingEventArgs e)
{
bIsClosing = true;
// Write the Logfile
doLog("whatever");
}
}
this.FormClosing is an event that gets triggered once your form starts closing (like clicking the close button), hence the name. You need your application to register that event like so:
this.FormClosing +=new FormClosingEventHandler(MyForm_FormClosing);
This insures that once the FormClosing event gets triggered, your MyForm_FormClosing will be called.
You can create a flag like bool bIsFormClosing and set that flag once your closing function get called.
Edit:
As I understand now by reviewing your answer and your comments, you want to know in your doLog function if the form is closing.
Here is another approach
`
public class YourForm : Form
{
private bool bIsClosing = false;
Private bool bClosingHandled = false;
public YourClass()
{
InitializeComponent();
this.FormClosing +=
new FormClosingEventHandler(MyForm_FormClosing);
}
private void txb_Validating(object sender, CancelEventArgs e)
{
doLog("Text 1");
}
private void dgv_CellValueChanged(object sender,
DataGridViewCellEventArgs e)
{
doLog("Text 2");
}
private void doLog(string txt)
{
// this is first called at closing...
if( bIsClosing )
{
// Do something
bClosingHandled = true;
this.close();
}
else
{
// Do someting different
}
}
private void MyForm_FormClosing(object sender, FormClosingEventArgs e)
{
If(!bClosingHandled)
{
bIsClosing = true;
e.Cancel = true;
return;
}
// Write the Logfile
doLog("whatever");
}
}`
This approach uses two flags... When you first receive a close event, you set the bIsClosing flag to true, cancels the event and return. Then once your dolog function get called, you force the close operation.
Related
I have 18 buttons on the child form "Control Test" which send event to the parent form
Out of 18 buttons, 14 are ON and OFF functionality, making 7 pairs as in the picture
The problem is raising the event for each button, it causes very long and messy code, both in the child and the parent form,
Is there any less complex way to do it? like I have done with the menu.
Child Form:
Child Form:
// B Plus Relay On Button
public event EventHandler BPRElayOnBtnClicked;
protected virtual void WhenBPRelayOnBtnClicked(EventArgs e)
{
BPRElayOnBtnClicked.Invoke(this, e);
}
private void BPRelayOn_btn_Click(object sender, EventArgs e)
{
WhenBPRelayOnBtnClicked(e);
}
// B Plus Relay OFF Button
public event EventHandler BPRElayOffBtnClicked;
protected virtual void WhenBPRelayOffBtnClicked(EventArgs e)
{
BPRElayOnBtnClicked.Invoke(this, e);
}
private void BPRelayOff_btn_Click(object sender, EventArgs e)
{
WhenBPRelayOffBtnClicked(e);
}
// B Minus Relay ON Button
public event EventHandler BMRElayOnBtnClicked;
protected virtual void WhenBMRelayOnBtnClicked(EventArgs e)
{
BMRElayOnBtnClicked.Invoke(this, e);
}
private void BMRelayOn_btn_Click(object sender, EventArgs e)
{
WhenBMRelayOnBtnClicked(e);
}
// B Minus Relay OFF Button
public event EventHandler BMRElayOffBtnClicked;
protected virtual void WhenBMRelayOffBtnClicked(EventArgs e)
{
BMRElayOffBtnClicked.Invoke(this, e);
}
private void BMRelayOff_btn_Click(object sender, EventArgs e)
{
WhenBMRelayOffBtnClicked(e);
}
...... //event for each button
Parent Form:
private void viewToolStripMenuItem_Click(object sender, EventArgs e)
{
ToolStripMenuItem menu = sender as ToolStripMenuItem;
switch (menu.Name)
{
case "controlTestToolStripMenuItem":
if (Application.OpenForms["CtrlTest"] is CtrlTest ctrlTest)
{
ctrlTest.Focus();
return;
}
ctrlTest = new CtrlTest();
ctrlTest.BPRElayOnBtnClicked += CtrlTest_BPRElayOnBtnClicked;
ctrlTest.BPRElayOffBtnClicked += CtrlTest_BPRElayOffBtnClicked;
ctrlTest.BMRElayOnBtnClicked += CtrlTest_BMRElayOnBtnClicked;
ctrlTest.BMRElayOffBtnClicked += CtrlTest_BMRElayOffBtnClicked;
ctrlTest.PreRElayOnBtnClicked += CtrlTest_PreRElayOnBtnClicked;
ctrlTest.PreRElayOffBtnClicked += CtrlTest_PreRElayOffBtnClicked;
ctrlTest.MdiParent = this;
ctrlTest.Show();
break;
.........//Other menus ...
default:
break;
private void CtrlTest_BPRElayOnBtnClicked(object sender, EventArgs e)
{
//Do something here
}
private void CtrlTest_BPRElayOffBtnClicked(object sender, EventArgs e)
{
//Do something here
}
private void CtrlTest_BMRElayOnBtnClicked(object sender, EventArgs e)
{
//Do something here
}
private void CtrlTest_BMRElayOffBtnClicked(object sender, EventArgs e)
{
//Do something here
}
For the on/off, take a look at the following control. For the others setup one event and work out logic similar to the on/off buttons.
Download the source, add the class project to your Visual Studio solution. Open the class project and change the .NET Framework currently set to 4, to your project's .NET Framework version.
Setup an enum where for each on/off button set it's tag to one of the members. this ways things are clearer using a switch and enums.
public enum OperationType
{
BPlusRelay,
BMinusRelay,
PreRelay,
CycleCount,
PairDown,
TestMode,
StandbyMode
}
In the child form, setup and event and set tags for each on/off control. Change the names to reflect their purpose, I simply added them quickly for demoing purposes.
public partial class ChildForm : Form
{
public delegate void OnClicked(OperationType operationType, bool state);
public event OnClicked ClickedEvent;
public ChildForm()
{
InitializeComponent();
SetProperties();
}
public void SetProperties()
{
ToggleSwitch1.Tag = OperationType.BPlusRelay;
ToggleSwitch2.Tag = OperationType.BMinusRelay;
ToggleSwitch3.Tag = OperationType.PreRelay;
ToggleSwitch4.Tag = OperationType.CycleCount;
ToggleSwitch5.Tag = OperationType.PairDown;
ToggleSwitch6.Tag = OperationType.TestMode;
ToggleSwitch7.Tag = OperationType.StandbyMode;
var list = Controls.OfType<JCS.ToggleSwitch>().ToList();
foreach (var toggleSwitch in list)
{
toggleSwitch.CheckedChanged += ToggleSwitchOnCheckedChanged;
}
}
private void ToggleSwitchOnCheckedChanged(object sender, EventArgs e)
{
var current = (JCS.ToggleSwitch)sender;
ClickedEvent?.Invoke((OperationType)current.Tag, current.Checked);
}
}
In the main form, show the child form, subscribe to the event above.
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void ShowChildFormButton_Click(object sender, EventArgs e)
{
var childForm = new ChildForm();
childForm.ClickedEvent += ClickedEvent;
try
{
childForm.ShowDialog();
}
finally
{
childForm.Dispose();
}
}
private void ClickedEvent(OperationType operationType, bool state)
{
switch (operationType)
{
case OperationType.BPlusRelay:
// TODO
break;
case OperationType.BMinusRelay:
// TODO
break;
case OperationType.PreRelay:
// TODO
break;
case OperationType.CycleCount:
// TODO
break;
case OperationType.PairDown:
// TODO
break;
case OperationType.TestMode:
// TODO
break;
case OperationType.StandbyMode:
// TODO
break;
}
}
}
Partly done form, and note you can change the size of the buttons.
I'd like the activated event to only run once. I've tried using an If condition but the Reload variable doesn't set to false and thus it keeps looping endlessly. Is there a way around this?
Form1.cs code:
private void Form1_Activated(object sender, EventArgs e)
{
if (Class1.Reload == true) {
Class1.Reload = false;
}
}
Class1.cs code:
public class Class1 {
public static void Refresh() { Reload = true; }
public static bool Reload { get; set; }
Just unsubscribe from the event the first time it is triggered.
private void Form1_Activated(object sender, EventArgs e)
{
this.Activated -= Form1_Activated;
// Do other stuff here.
}
While CathalMF's solution is valid, I'll post the solution I implemented, whose aim was to refresh a DatagridView when I come back to the main form.
private void Form1_Activated(object sender, EventArgs e) {
if (Class1.Reload == true) {
Activated -= Form1_Activated;
Class1.Reload = false;
//Here I implement the code to refresh a DatagridView
Activated += Form1_Activated;
}
}
Class1.cs stays the same.
I have a button called btnChallenge. The desired action is when it is clicked, the form cannot be closed.
Here is what I have so far:
public void btnChallenge_Click(object sender, EventArgs e) { }
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
// not sure on this if statement
if (btnChallenge.Click)
{
e.Cancel = true;
}
}
You could try it this way:
Declare a private variable inside a form:
private bool _closedFromMyButton;
Then on FormClosing event check that property:
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (_closedFromMyButton) // If closed from MyButton, don't do anything. let the form close.
return;
Hide(); // Hide the form (or not, it's up to you; this is useful if application has an icon in the tray)
e.Cancel = true; // Cancel form closing
}
Then on some button click (if desired), put this code to close the form only from that button (or menuitem or toolbar button, etc.):
private void MyButtonClick(object sender, EventArgs e)
{
_closedFromMyButton = true;
Application.Exit(); // Or this.Close() if you just want to close the form.
}
You could define a variable which goes to true when you press the button and check on close if the variable is true
e.g.
private bool btnClicked = false;
public void btnChallenge_Click(object sender, EventArgs e)
{
btnClicked = true;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if(btnClicked)
{
e.Cancel=true;
}
}
You can just call the this.Close() method, this will call the Form1_FormClosing event:
public void btnChallenge_Click(object sender, EventArgs e)
{
this.Close();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
//code here...
}
If you want to prevent the users by closing your form just after they have pressed some other button, then this code will help you.
private bool close_state=false; // hold the button state
// method to change the close_state by button click
private void Button1(object sender, EventArgs e)
{
close_state = true;
// if required you can toggle the close_state using an if statement
}
// Then on FormClosing event check that property:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (close_state) {// If the button is pressed
e.Cancel = true; // Cancel form closing
}
}
You may implement some other way to close the form....
I have an app that show a form call System Parameters and i want the form to only pop one time so that the user cant open the same window million times. I tried
private void SystemParametersClick(object sender, EventArgs e)
{
Xpan sp = new Xpan();
sp.CurrentItem = this.GetCaller(sender);
if (sp.Visible==false)
{
sp.Show();
}
}
It doesnt work because it is not the same instance. :(
How do i make it only pop once?
Why do you instantiate the form within the method? Simply instantiate it within the parent class and only call the Show() method within the click event.
public class MainForm : Form
{
private Xpan _Xpan;
public MainForm()
{
InitializeComponent();
_Xpan = new Xpan();
}
private void SystemParametersClick(object sender, EventArgs e)
{
_Xpan.Show();
}
}
Maybe this simple approach would suffice?
private bool has_been_shown = false;
private void SystemParametersClick(object sender, EventArgs e)
{
if(!has_been_shown)
{
has_been_shown = true;
Xpan sp = new Xpan();
}
}
First disable closing for Xpan form. You can do it by defining OnFormClosing event handler.
private void Xpan_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
Hide();
}
Then define your Xpan form as a class member of the parent form, e.g.:
private readonly Xpan _sp = new Xpan();
And finally defile your Click handler this way:
private void SystemParametersClick(object sender, EventArgs e)
{
if (!_sp.Visible)
{
_sp.Show();
}
else
{
_sp.Activate();
}
}
That's it.
I am trying to call one EventHandler method from another. For example, I would like to link Logout button with form exit, so I have this code:
private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
{
if (MessageBox.Show("Bla, bla?", "Logout", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK)
{
e.Cancel = false;
}
else
{
e.Cancel = true;
}
}
and I want to call it from this event:
private void btnLogOut_Click(object sender, EventArgs e)
{
FormMain_FormClosing(null, 'not sure what goes here');
}
Try this:
private void btnLogOut_Click(object sender, EventArgs e)
{
FormMain_FormClosing(null, null);
}
or
private void button1_Click(object sender, EventArgs e)
{
Form1_FormClosing(
null,
new FormClosingEventArgs(CloseReason.UserClosing, false));
}
Even if my answer cover how to link event handlers part, this particular solution leads you to a problem: form won't close clicking button.
Correct solution is
private void button1_Click(object sender, EventArgs e)
{
Close();
}
Handling the event and asking for confirmation are seperate things:
private static bool UserConfirmedToLogout()
{
return MessageBox.Show("Bla, bla?", "Logout", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK;
}
private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = !UserConfirmedToLogout();
}
private void btnLogOut_Click(object sender, EventArgs e)
{
Close();
}
When Close() is called, the FormClosing event is fired too.