why form_closing() is firing twice? - winforms

I am working on a windows form application. I want to show user a message stating close reason when user clicks "X" button in the main window.With "X" button i mean "close" button in "minimize","maximize" and "close" tray in windows.
I have written this code.
private void frmIMS_FormClosing(object sender, FormClosingEventArgs e)
{
if (MessageBox.Show("This application is closing down because of " + e.CloseReason.ToString() + ". Do you really want to close it ?", "", MessageBoxButtons.YesNo) == DialogResult.No)
{
e.Cancel = true;
}
else
{
Application.Exit();
}
}
Now what happens is,If user clicks no to message box,event is discarded and when user clicks yes,form_closing() fires again and shows other messagebox.So messagebox is shown twice.I want to show it once.Please help and tell why is it firing twice.

You can skip the else part of your application. If your form is main form of application, it will exit anyway.
Application.Exit() causes all windows to close. Your "first" close is still pending, so form is not yet closed and Application.Exit() tries to close your form for the second time.
You can try this:
bool closingPending = false;
private void frmIMS_FormClosing(object sender, FormClosingEventArgs e)
{
if (closingPending) return;
if (MessageBox.Show("This application is closing down because of " + e.CloseReason.ToString() + ". Do you really want to close it ?", "", MessageBoxButtons.YesNo) == DialogResult.No)
{
e.Cancel = true;
}
else
{
closingPending = true;
Application.Exit();
}
}

I know this thread is a bit old, but why not:
$Application.OpenForms["NameOfMainForm"].Close;

I know this is old and I stumbled upon this question as I encountered the same behavior. I'm using .Net 4.5 and here is how I went about this issue:
private void frmIMS_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
if (MessageBox.Show("This application is closing down because of " + e.CloseReason.ToString() + ". Do you really want to close it ?", "", MessageBoxButtons.YesNo) == DialogResult.No)
{
e.Cancel = true;
}
else
{
Application.Exit();
}
}
}
You can find more information about CloseReason enumeration here: http://msdn.microsoft.com/en-us/library/system.windows.forms.closereason.aspx

Why Application.Exit in the else branch? This is done automatically and may solve your problem.

Private Sub ClaimEditor_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
If MsgBox("Edit mode active. Exit without saving?", MsgBoxStyle.YesNo Or MsgBoxStyle.Question, "Edit mode") <> MsgBoxResult.Yes Then
e.Cancel = True
Exit Sub
'Else
' e.Cancel = False
End If
WriteIntoRregistry()
RemoveHandler Me.FormClosing, AddressOf ClaimEditor_FormClosing
Application.Exit()
End Sub

I had this same issue and determined that the Application.Exit() was calling the FormClosing event.
Only put Application.Exit() in the FormClosed event, instead of the FormClosing event.
Use this code:
private void frmIMS_FormClosing(object sender, FormClosingEventArgs e)
{
if (closingPending) return;
if (MessageBox.Show("This application is closing down because of " +
e.CloseReason.ToString () + ". Do you really want to close it ?", ""
, MessageBoxButtons.YesNo) == DialogResult.No)
{
e.Cancel = true;
}
else
{
closingPending = true;
// Application.Exit(); <-- Remove this
}
private void frmIMS_FormClosing(object sender, FormClosingEventArgs e)
{
Application.Exit(); <-- Put it here.
}

I think #Tornado726 already answered the best possible answer for all. But there is just one Copy/Paste mistake I guess (typed form_closing twice)
Private Sub FORM1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
Select Case (MessageBox.Show("Do you really want to close?", "Quit", MessageBoxButtons.YesNo))
Case MsgBoxResult.No
e.Cancel = True
End Select
End Sub
Private Sub FORM1_FormClosed(sender As Object, e As FormClosedEventArgs) Handles MyBase.FormClosed
Application.Exit()
End Sub

try this: this will be a great help
private void Master_FormClosing(object sender, FormClosingEventArgs e)
{
DialogResult result = MessageBox.Show("Do you really want to exit the program?", "Data Patch", MessageBoxButtons.YesNo);
if (result != DialogResult.Yes)
{
e.Cancel = true;
}
}

Application.Exit() calls frmX_FormClosing().
That's why FormClosing() gets called twice.

I've just had that same problem. This is what I did to get around it:
private void frmIMS_FormClosing(object sender, FormClosingEventArgs e)
{
if (MessageBox.Show("This application is closing down because of " + e.CloseReason.ToString() + ". Do you really want to close it ?", "", MessageBoxButtons.YesNo) == DialogResult.No)
{
e.Cancel = true;
}
else
{
try
{
Environment.Exit(0); // It will try to close your program "the hard way"
}
catch (Exception)
{
Application.Exit(); // If a Win32 exception occurs, then it will be able to close your program "the normal way"
}
}
}
I'm sure it's going to work for you, if you haven't already found a solution or even given up on that code as it's been quite a while.

Related

if Right button pressed on console

Good morning,
I would like to know if my right mouse button is held down.
For this I thought of System.Windows.Input.Mouse but I get this error if I execute the following code:
while (true)
{
if (Mouse.RightButton == MouseButtonState.Pressed)
{
}
}
Error : Unmanaged exception: System.InvalidOperationException: The calling thread must be in STA mode, as required by the name
Is there an alternative or something that would work as a console?
Thanks
Try using it inside a function like this :
private void PressLeftButton(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
MessageBox.Show("The Left Mouse Button is pressed");
}
}

Restrict button click on telerik radgridview cellValidating event - winforms

I was testing its cellValidating event which has some problem or may be i am missing something. When the radgridview cell in in edit mode i cannot click anywhere on the form thats fine here. But when i click on button, code executes and my form hangs. So my question is how can i disable code execution on button click when radgridview cell is in edit mode during cellValidating event. Note: When i debug code and insert breakpoints on cellValidating event and button. Code works well and button code does not executes. Following is the code that i am using.If anyone can immediate answer i shall be very thankful to him.
Private Sub rgv_CellValidating(sender As System.Object, e As Telerik.WinControls.UI.CellValidatingEventArgs) Handles rgv.CellValidating
Dim column As GridViewDataColumn = TryCast(e.Column, GridViewDataColumn)
If TypeOf e.Row Is GridViewDataRowInfo AndAlso column IsNot Nothing AndAlso column.Name = "ProductId" Then
If String.IsNullOrEmpty(DirectCast(e.Value, String)) OrElse DirectCast(e.Value, String).Trim() = String.Empty Then
e.Cancel = True
DirectCast(e.Row, GridViewDataRowInfo).ErrorText = "Validation error!"
Else
DirectCast(e.Row, GridViewDataRowInfo).ErrorText = String.Empty
End If
End If
The phenomnenon you describe about buttoncode still executing also is true for ribbonmenu buttons and ribbonmenutabs. The hanging up problem I couldn't reproduce so I guess it has to do with the code of your executed buttons there.
For a possible workaround you could put a private variable into your form and in the cellvalidation code set it to true if an error occurs and false if no error occurs (and naturally set it fo false in the form initialization code).
Then within the buttons code you test for the variables value if its true no code is executed.
Thus if you have a ribbonform (or any other form) as class:
public partial class MF : RadRibbonForm
{
private bool _hasValidationError;
public MF()
{
...//Normal construction handler code
_hasValidationError = false;
}
void MF_CellValidating(objec sender, CellValidatingEventArgs e)
{
.....//Do validation and set e.Cancel true if the validation fails.
if (e.Cancel)
{
hasValidationError = true;
}
else
{
hasValidationError = false;
}
}
private void MyButton_Click(object sender, EventArgs e)
{
if (_hasValidationError)
{
// Before return you could put in a messagebox that there are cell errors that need to be looked at first
return;
}
else
{
.......//Button code execution occurs here
}
}
With this code you can make sure that the code of the buttons you don't want to be executed won't get executed on an Cell validation error.
The Code is in C# but should work similar for VB winforms.
This seems to be a known issue with the grid issue link.
There is also work around for the issue provided:
bool validating = false;
void radGridView1_CellValidating(object sender, Telerik.WinControls.UI.CellValidatingEventArgs e)
{
if (e.Value.ToString().Length < 5)
{
e.Cancel = true;
validating = true;
e.Row.ErrorText = "Validation error!";
}
else
{
validating = false;
}
}
private void radButton1_Click(object sender, EventArgs e)
{
if (!validating)
{
Debug.WriteLine("Executed");
}
}

Keep connection always open for datatable twoway bind?

I'm working on a WPF project which includes update/delete/insert operation on many tables. For simplicity, I use a datagrid for each table. The users can operate on these tables directly. Once done, click a button, the tables in database get updated. Twoway bind is perfect in this case. Below code seems working fine.
However, one thing I do not like is: the _DBConnection is always open. It is closed until the form exists. Usually, I always open connection whenever I need to, use it, close it immediately.
So, my question is: is below code the correct way to do the twoway bind?
thanks
public partial class MainWindow : Window
{
private OleDbConnection _DBConnection;
private OleDbDataAdapter _DataAdapterAdmin;
private DataSet _DataSetAdmin;
public MainWindow()
{
InitializeComponent();
}
private void InitAdminGrid()
{
string cmd = "SELECT * FROM Admin ORDER BY LastName";
_DataAdapterAdmin = new OleDbDataAdapter(cmd, _DBConnection);
_DataSetAdmin = new DataSet();
_DataAdapterAdmin.Fill(_DataSetAdmin);
dgAdministration.BeginInit();
dgAdministration.DataContext = _DataSetAdmin.Tables[0];
dgAdministration.Items.Refresh();
dgAdministration.EndInit();
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
string connectionString = clsDataAccess.GetConnectionString();
_DBConnection = new OleDbConnection(connectionString);
_DBConnection.Open();
InitAdminGrid();
}
private void btnStart_Click(object sender, RoutedEventArgs e)
{
try
{
OleDbCommandBuilder cmd = new OleDbCommandBuilder(_DataAdapterAdmin);
_DataAdapterAdmin.Update(_DataSetAdmin);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "Exception", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (_DBConnection != null)
{
_DBConnection.Close();
_DBConnection.Dispose();
}
}
}

Working with ProgressBar and ComboBox

I'm in trouble with a Marquee ProgressBar. I need to execute a method (refreshList()) to get a List<string>. Then I assign this List to a ComboBox, so ComboBox refreshes with the new Items. As refreshList() take 3 or 4 sec, I wanted to run a Marquee ProgressBar. But I couldn't. ProgressBar is ok, but ComboBox doesn't load new Items.
My refreshList() method:
private void refreshList(List<string> list)
{
albumList.DataSource = null;
albumList.DataSource = list;
}
I have the following code, it works fine:
private void changeDirectoryToolStripMenuItem_Click(object sender, EventArgs e)
{
fbd.RootFolder = Environment.SpecialFolder.MyComputer;
folderPath = "";
if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
folderPath = fbd.SelectedPath;
refreshList(N.getList(folderPath));
}
}
But I added a ProgressBar and wrote this code:
private void changeDirectoryToolStripMenuItem_Click(object sender, EventArgs e)
{
fbd.RootFolder = Environment.SpecialFolder.MyComputer;
folderPath = "";
if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
folderPath = fbd.SelectedPath;
bgWorker.WorkerReportsProgress = true;
bgWorker.RunWorkerAsync();
}
}
And I placed refreshList() in doWork() method:
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
refreshList(N.getList(folderPath));
}
But unfortunately this isn't working. Can anybody help me solving this problem? Thanks in advance.
You can use the MarqueeAnimationSpeed and Value properties of the ProgressBar control to stop and start the Marquee. There's no need to use WorkerReportsProgress* as you aren't incrementing a normal progress bar - you just want to "spin" the Marquee.
You can do something like the following:
public Form1()
{
InitializeComponent();
//Stop the progress bar to begin with
progressBar1.MarqueeAnimationSpeed = 0;
//If you wire up the event handler in the Designer, then you don't need
//the following line of code (the designer adds it to InitializeComponent)
//backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
}
private void changeDirectoryToolStripMenuItem_Click(object sender, EventArgs e)
{
fbd.RootFolder = Environment.SpecialFolder.MyComputer;
folderPath = "";
if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
folderPath = fbd.SelectedPath;
//This line effectively starts the progress bar
progressBar1.MarqueeAnimationSpeed = 10;
bgWorker.RunWorkerAsync(); //Calls the DoWork event
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = N.getList(folderPath); //Technically this is the only work you need to do in the background
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//these two lines effectively stop the progress bar
progressBar1.Value = 0;
progressBar1.MarqueeAnimationSpeed = 0;
//Now update the list with the result from the work done on the background thread
RefreshList(e.Result as List<String>);
}
private void RefreshList(List<String> results)
{
albumList.DataSource = null; //You don't need this line but there is no real harm.
albumList.DataSource = list;
}
Remember to wire up the RunWorkerCompleted event to backgroundWorker1_RunWorkerCompleted via the Properties bar, Events section in the designer.
To begin with, we start the ProgressBar's animation by setting the MarqueeAnimationSpeed property to a non-zero positive number as part of your successful folder selection.
Then, after calling RunWorkerAsync, the code builds your list in the DoWork method, then assigns the result to the DoWorkEventArgs, which get passed to the RunWorkerCompleted event (which fires when DoWork is finished).
In the backgroundWorker1_RunWorkerCompleted method, we stop the progress bar (and set it's value to zero to effectively return it to it's original state), and then we pass the list to the refreshList method to databind it and populate the ComboBox.
Tested using VS2012, Windows Forms, .Net 4.0 (with a Thread.Sleep to emulate the time taken for N.getList)
*WorkerReportsProgress, and the associated ReportProgress method/event are used when you want to increment the progress bar - you can tell the GUI that you are 10% done, 20% done, 50% done etc etc.

Detecting the user pressing F10 in WPF

My WPF application has behaviour triggered by the functions keys (F1-F12).
My code is along these lines:
private void Window_KeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.F1:
...
case Key.F2:
...
}
}
This works for all F-keys except F10. Debugging, I find that e.Key == Key.System when the user presses F10.
In the enum definition, F10 = 99 and System = 156, so I can rule out it being a duplicate enum value (like PageDown = Next = 20).
So, how do I tell when the user presses F10?
Is it safe to check for Key.System instead? This feels a little dirty - might it be possible that Key.System would ever result from some other key being pressed? Or is there some setting somewhere that will make F10 report as Key.F10?
In addition to Yacoder's response, use the following to check for the F10 key:
case Key.System:
if (e.SystemKey == Key.F10)
{
// logic...
}
The SystemKey property will tell you which System key was pressed.
F10 launches the window menu. It's the same in all Windows apps.
It seems that Key.System is the expected value for the F10 key.
Answer with DataContext:
public partial class BankView : UserControl
{
public BankView()
{
InitializeComponent();
this.KeyDown += new KeyEventHandler(BankView_KeyDown);
}
private void BankView_KeyDown(object sender, KeyEventArgs e)
{
try
{
switch (e.Key)
{
case Key.F4:
((BankViewModel)DataContext).OpenAccount();
break;
}
}
catch (Exception ex)
{
...
}
}
This worked for me, for F1
Private Sub Window_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
If (e.Key = Key.F1) Then
ShowHelp()
End If
End Sub

Resources