Strange ToolStripButton click to open an OpenFileDialog behavior - c#

I found a strange ToolStripButton double click problem. These steps will reproduce the problem:
Create a Windows Form Application.
Add a ToolStrip on the main form.
Add a ToolStripButton on the ToolStrip.
Add an OpenFileDialog on the main form.
Double click the ToolStripButton's Click event on the property toolbox.
Add this in toolStripButton1_Click method:
openFileDialog1.ShowDialog();
Start debug.
Quickly double click the ToolStripButton.
Here comes the problem. First, an open file dialog pops up, and I close it, then another dialog pops up. This shouldn't happen. I close it again, then the main form may have some redraw problem. Finally, I close the main form, but the program is still running.
Please try it yourself and let me know if all those happens.
Why those happens? What should I do to solve it?
You can use this to reproduce the problem:
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace WinForm
{
class MyForm : Form
{
private IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
openFileDialog1 = new OpenFileDialog();
toolStrip1 = new ToolStrip();
toolStripButton1 = new ToolStripButton();
toolStrip1.SuspendLayout();
this.SuspendLayout();
toolStrip1.Items.AddRange(new ToolStripItem[] { toolStripButton1 });
toolStripButton1.Text = "toolStripButton1";
toolStripButton1.Click += new EventHandler(toolStripButton1_Click);
this.Controls.Add(toolStrip1);
toolStrip1.ResumeLayout(false);
toolStrip1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
private OpenFileDialog openFileDialog1;
private ToolStrip toolStrip1;
private ToolStripButton toolStripButton1;
public MyForm()
{
InitializeComponent();
}
private void toolStripButton1_Click(object sender, EventArgs e)
{
openFileDialog1.ShowDialog();
}
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyForm());
}
}
}

Why those happens?
I really don't know, it's a surprise for me!!
What should I do to solve it?
This is a simple workaround:
private bool clicked = false;
private void toolStripButton1_Click(object sender, EventArgs e)
{
if (clicked) return;
clicked = true;
openFileDialog1.ShowDialog();
clicked = false;
}
EDITED:
I suppose that problem is not double-click itself, but OpenFileDialog behaviour.
If you try this code the error disappears even for (accidental) double-click:
private void toolStripButton1_Click(object sender, EventArgs e)
{
using (OpenFileDialog dlg = new OpenFileDialog()
{
Title = "Open file",
Filter = "PDF files|*.pdf|All files|*.*"
})
{
dlg.ShowDialog();
Debug.WriteLine(dlg.FileName);
}
}
If you use tsb1.DoubleClickEnabled = true the error disappear... but I'm not sure this is a good solution

I decided to use this (for now):
private void toolStripButton1_Click(object sender, EventArgs e)
{
toolStripButton1.Enabled = false;
openFileDialog1.ShowDialog();
toolStripButton1.Enabled = true;
}

Related

fast-report close designer without save dialog

I'm working on an application that uses fast-report.
If I modified the report and close the designer window I get asked if I want to save "Untitled.frx". How can I prevent this dialog from appearing?
Thanks in advance
There is AskSave property:
var report = new Report();
Config.DesignerSettings.DesignerLoaded += (object sender, EventArgs e) =>
{
report.Designer.AskSave = false;
};
report.Design();
This is how I solved the problem. The DesignerSettings_DesignerClosed method is to prevent problems if i reopen the Designer later.
Thanks #Grzegorz Brzęczyszczykiewicz for the tip with AskSave().
...
{
Config.DesignerSettings.DesignerLoaded += DesignerSettings_DesignerLoaded;
Config.DesignerSettings.DesignerClosed += DesignerSettings_DesignerClosed;
Report.ReportData.Design(false);
}
private void DesignerSettings_DesignerClosed(object sender, EventArgs e) {
Config.DesignerSettings.DesignerLoaded -= DesignerSettings_DesignerLoaded;
Config.DesignerSettings.DesignerClosed -= DesignerSettings_DesignerClosed;
}
private void DesignerSettings_DesignerLoaded(object sender, EventArgs e) {
Report.ReportData.Designer.AskSave = false;
}

WPF dialogBox Don't close the application

I made a custom dialog box in WPF. I want , when the user clicks X the dialogBox will be opened, if he wants to exit he should click "yes", if not he should click "no".
static public bool? close;
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
this.Hide();
WindowClose windowClose = new WindowClose();
windowClose.ShowDialog();
close = windowClose.DialogResult;
if (close == true)
{
Application.Current.Shutdown();
}
else
{
//DONT CLOSE THE APPLICATION AND SHOW THE CURRENT WINDOW
}
}
the code of the dialog box:
private void button1_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = true;
this.Close();
}
private void button2_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = false;
this.Close();
}
Not sure if it works differently in WPF, but in standard winforms in the code for the dialog box you'd set (for example) the DialogResult to DialogResult.OK (yes) and DialogResult.Cancel (no). You wouldn't need to close the form as this is done automatically when you set the DialogResult
Then in the main form you'd have
If (windowClose.ShowDialog() == DialogResult.OK
{
Application.Current.Shutdown();
}
else
{
//DONT CLOSE THE APPLICATION AND SHOW THE CURRENT WINDOW
}

Bring dialog window to front

I am showing a window on a button click like this:
private void showWindow(object obj)
{
var dialog = new AddItemView();
dialog.Show();
}
If the button is clicked again, while this window is still open, how do I bring this window to the front and not create a new one?
Just store the dialog object and check whether it's already been created in showWindow.
Used the windows Closed event to clear the reference to the dialog object.
AddItemView dialog;
private void showWindow(object obj)
{
if ( dialog == null )
{
dialog = new AddItemView();
dialog.Show();
dialog.Owner = this;
dialog.Closed += new EventHandler(AddItemView_Closed);
}
else
dialog.Activate();
}
void AddItemView_Closed(object sender, EventArgs e)
{
dialog = null;
}
Just a quick sketch but this should do what you want:
Window1 W = new Window1();
private void Button_Click(object sender, RoutedEventArgs e)
{
if (W.IsVisible)
W.Activate();
else
W.Show();
}
If this does not do it, maybe I have misread your question.
Edited to correct a bug.
Add this on the class constructor where you are instantiating the window. A window cannot be closed after is opened.
W.Closing += (s, e) =>
{
e.Cancel = true;
((Window)s).Hide();
};

I need to close the previous active window when navigating a windows form with menustrip

I'm putting together a simple UI that interacts with a SQL database. My problem is a UI problem, ever time a menustrip item is selected, it opens a new active window. How do I set this up to close the previous active window? I've tried using Form.Close();, but that just closes everything.
private void addCampusToolStripMenuItem_Click(object sender, EventArgs e)
{
if_add_campus go = new if_add_campus();
go.Show();
}
private void addDepartmentToolStripMenuItem_Click(object sender, EventArgs e)
{
if_add_dept go = new if_add_dept();
go.Show();
}
private void addEmployeToolStripMenuItem_Click(object sender, EventArgs e)
{
if_add_employee go = new if_add_employee();
go.Show();
}
Just keep track of the last form you created in a variable:
private Form lastForm;
private void showForm(Form frm) {
frm.FormClosed += (sender, ea) => {
if (object.ReferenceEquals(lastForm, sender)) lastForm = null;
};
frm.Show();
if (lastForm != null) lastForm.Close();
lastForm = frm;
}
And use showForm() to display your forms:
private void addCampusToolStripMenuItem_Click(object sender, EventArgs e)
{
showForm(new if_add_campus());
}
Not tested, should be close.

systemevents.sessionended is not being caught or fired

Please in my code i try to catch win32.systemevents.sessionended event to procede with saving of my app data by the end of session in case the app is not closed manually .. some time ago this has been workin and now that i had my project grown a lil it is not any more..? i have tried to find something meaningfull for few days but found nothing really.. when i try to catch another systemevent like MonitorResolutionChanged it works well but this one not. I have also tried to register within the mainWindow (app form ..), nothing :-( Please any idea?
I think all the relevant information should be in the beginning till void Main but i put it all in case you would need or want to see more .. Thanx a lot Tomas
My code:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Threading;
using MovablePython; // my own class within this project
using Avn; //my own referenced assembly
namespace DirDist
{
class Program
{
private static string appGuid = "Cddbserviceman";
private static System.Windows.Forms.ContextMenu nIMenu;
internal static System.Windows.Forms.NotifyIcon notifyIcon1;
private static MenuItem showItem;
public static MenuItem justCDsItem;
private static MenuItem searchItem;
private static MenuItem settingsItem;
private static MenuItem quitItem;
internal static Form1 mainWindow;
private static Hotkey hk;
internal static Registration.LicenceState mode; // app mode - registered/trial/blocked/demaged ..
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
using (Mutex mutex = new Mutex(false, appGuid))
{
if (!mutex.WaitOne(0, false))
{
MessageBox.Show("CDDB is already running on your machine \n (Check status bar for access ..)");
return;
}
GC.Collect();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
mode = Registration.Startup();
Program.mainWindow = new Form1();
mainWindow.Activate();
//mainWindow.Validate();
//mainWindow.Update();
mainWindow.Visible = false;
PutIcon();
//Microsoft.Win32.SystemEvents.SessionEnded += SystemEvents_SessionEnded;
Microsoft.Win32.SystemEvents.SessionEnded += new Microsoft.Win32.SessionEndedEventHandler(SystemEvents_SessionEnded);//**zkousime zda funguje pro hibernaci ..
RegisterHotKey(true);
Application.Run();
}
}
static void SystemEvents_SessionEnded(object sender, Microsoft.Win32.SessionEndedEventArgs e)
{
//MessageBox.Show("SessionEnded fired");
RegisterHotKey(false);
notifyIcon1.Visible = false;
notifyIcon1.Dispose();
notifyIcon1 = null;
if (!mainWindow.dBSaved) mainWindow.SaveDb(Form1.settings.dBPath);
if (mainWindow.index != null) mainWindow.SaveIndex(Form1.settings.indexPath);
Microsoft.Win32.SystemEvents.SessionEnded -= new Microsoft.Win32.SessionEndedEventHandler(SystemEvents_SessionEnded);
mainWindow.Close();
}
// zaregistruje globalni hotkey ctrl+shift+F Pro hledani
private static void RegisterHotKey(bool active)
{
if (!active)
{
if (hk != null) hk.Unregister();
}
else
{
if(hk ==null) hk = new Hotkey();
hk.KeyCode = Keys.F;
//hk.Windows = true;
hk.Shift = true;
hk.Control = true;
//hk.Pressed += delegate { Console.WriteLine("Windows+1 pressed!"); };
hk.Pressed += delegate { searchItemClick(new object(), new EventArgs()); };
if (hk.GetCanRegister(mainWindow)) hk.Register(mainWindow);
else ; // just do nothing
}
}
private static void PutIcon()
{
if (notifyIcon1 == null)
{
showItem = new MenuItem ("&Show interface", new System.EventHandler (showInfaceClick));
justCDsItem = new MenuItem ("&Jus'CDs",new System.EventHandler ( justCDsClick));
justCDsItem.Checked = Form1.settings.justCDs;
searchItem = new MenuItem("Search CDDB",new System.EventHandler (searchItemClick));
searchItem.Shortcut = Shortcut.CtrlShiftF;
searchItem.ShowShortcut = true;
settingsItem = new MenuItem("Settings", new System.EventHandler(settingsItemClick));
quitItem = new MenuItem("&Quit", new System.EventHandler(quitItemClick));
nIMenu = new System.Windows.Forms.ContextMenu(new MenuItem[5] { showItem, justCDsItem, searchItem,settingsItem, quitItem });
notifyIcon1 = new System.Windows.Forms.NotifyIcon();
notifyIcon1.ContextMenu = nIMenu;
notifyIcon1.Icon = new System.Drawing.Icon(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Icon1.ico");
//notifyIcon1.Icon = new System.Drawing.Icon(System.IO.Path.GetDirectoryName(
//System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase ) + "Icon1.ico");
//notifyIcon1.Icon = new System.Drawing.Icon("Icon1.ico");
notifyIcon1.DoubleClick += new EventHandler(notifyIcon1_DoubleClick);
notifyIcon1.Visible = true;
}
}
/* private static void notifyIcon1_MouseMove(object sender, MouseEventArgs mea)
* aby to fungovalo je treba upravit contextmenu na contextmenustrip a taky ty items .. az nakonec
* je tu kolem uz rozdelana priprava ..
{
notifyIcon1.ShowBalloonTip(2000,AppName,"Active",ToolTipIcon.None);
} */
// clicks on NotificationIcon context menu ..
private static void showInfaceClick(object sender, EventArgs e)
{
mainWindow.tabControl1.SelectedIndex = 0;
mainWindow.Show();
}
private static void justCDsClick(object sender, EventArgs e)
{
Form1.settings.justCDs = mainWindow.checkBox1.Checked = justCDsItem.Checked = !Form1.settings.justCDs;
if (mainWindow.Visible) mainWindow.Update();
}
private static void searchItemClick(object sender, EventArgs e)
{
mainWindow.tabControl1.SelectedIndex = 1 ;
//this.Size = new Size(this.Width, SystemInformation.PrimaryMonitorSize.Height);
mainWindow.Location = new System.Drawing.Point(SystemInformation.PrimaryMonitorSize.Width - mainWindow.Width, SystemInformation.PrimaryMonitorSize.Height - mainWindow.Height);
//mainWindow.Location = new System.Drawing.Point(880, 500);
mainWindow.Show();
}
private static void settingsItemClick(object sender, EventArgs e)
{
mainWindow.tabPage3_GotFocus(new Object(), new EventArgs());
mainWindow.tabControl1.SelectedIndex = 2;
mainWindow.Show();
}
public static void quitItemClick(object sender, EventArgs e)
{
if (DialogResult.Cancel == MessageBox.Show("Really exit application and stop scanning?",Form1.AppName,MessageBoxButtons.OKCancel,MessageBoxIcon.Question)) return;
if (!mainWindow.dBSaved) mainWindow.SaveDb(Form1.settings.dBPath);
//if (mainWindow.index != null) mainWindow.SaveIndex(Form1.settings.indexPath);
if (Form1.settings.fileIndex) mainWindow.SaveIndex(Form1.settings.indexPath);
mainWindow.Close();
mainWindow = null;
notifyIcon1.Visible = false;
Application.Exit();
}
static void notifyIcon1_DoubleClick(object sender, EventArgs e)
{
//throw new NotImplementedException();
//if (!mainWindow.Visible) mainWindow.WindowState = FormWindowState.Normal; else mainWindow.WindowState = FormWindowState.Minimized;
//if (!mainWindow.Visible) mainWindow.Show(); else mainWindow.Hide();
if (!mainWindow.Visible) mainWindow.Visible = true; else mainWindow.Visible = false;
}
}
}
OK. So here is the catch and solution . In Windows it is not determined whether win32.systemevents.sessionended shall be risen or form.close() will be called first by operating system. moreover it seems that if form.close() is called first then sessionended is omited even though form is not closed and disposed due to canceling closing process. in my system this behaviour changed after i ran some registry cleaning software. anyway understanding this we have to take care of both possible scenarios.
1. catch win32.systemevents.sessionended (or sessionending) event whatever suits our needs better and be
.
.
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Microsoft.Win32.SystemEvents.SessionEnded += new Microsoft.Win32.SessionEndedEventHandler(SystemEvents_SessionEnded);
Program.mainWindow = new Form1();
mainWindow.Activate();
mainWindow.Visible = false;
PutIcon();
RegisterHotKey(true);
Application.Run();
}
}
public static void SystemEvents_SessionEnded(object sender, Microsoft.Win32.SessionEndedEventArgs e)
{
// do whatever needed and exit application ..
RegisterHotKey(false);
notifyIcon1.Visible = false;
notifyIcon1.Dispose();
notifyIcon1 = null;
if (!mainWindow.dBSaved) mainWindow.SaveDb(Form1.settings.dBPath);
if (mainWindow.index != null) mainWindow.SaveIndex(Form1.settings.indexPath);
Microsoft.Win32.SystemEvents.SessionEnded -= new Microsoft.Win32.SessionEndedEventHandler(SystemEvents_SessionEnded);
if (mainWindow != null)
{
mainWindow.Dispose();
mainWindow = null;
}
Application.Exit();
}
2. properly override form.OnClosing() because this is being called when form is closing either manually by user or by system when shuting down, loging off etc. or create hanler for main form.Closing:
public Form1()
{
this.Closing += new CancelEventHandler(this.Form1_Closing);
InitializeComponent();
}
private void Form1_Closing(Object sender, CancelEventArgs e)
{
if (systemShutdown) Program.SystemEvents_SessionEnded(this, new Microsoft.Win32.SessionEndedEventArgs(Microsoft.Win32.SessionEndReasons.SystemShutdown));
else
{
e.Cancel = true;
this.Hide();
}
}
just want to mention that message pump must be runnig in order to sessionended be risen. Application.run() accomplishes that.
in my case as you can see i had to dig even deeper as i had closing redirected just to hide the app not to close it ( i just hide the app to notification irea icon and close it manually when i need .. ) and so i had to use some kind of way to specify the situation when this is called because sender is unfortunatelly and unexpectedly always this ..?
this is done by overring WndProc and catching propper message .here you can listen pretty much to everything inside windows ( like disc inserted / removed )but it is hooked only to a form and implementation gets often not so simple as you have to manully define various values and structs and compare against those values .. other then that its pretty simple:
private static int WM_QUERYENDSESSION = 0x11;
private static bool systemShutdown = false;
protected override void WndProc(ref System.Windows.Forms.Message m)
{
if (m.Msg==WM_QUERYENDSESSION)
{
systemShutdown = true;
}
base.WndProc(ref m);
}
this was found here:
http://msdn.microsoft.com/en-us/library/microsoft.win32.systemevents.sessionending.aspx
Thinking a bit further we can possibly omit point 1 as system shall probably always try to call mainForm.close() but i keep it as i can not be certain about windows behaviour once it runs those things in different order again .. and also it is the mainly suggested solution for reacting to system shut down ..
hope this is helpfull for someone. greets from prague tomas
Here is something that you could try
For a shutdown, override the OnShutdown method:
protected override void OnShutdown()
{
//your code here
base.OnShutdown();
}
For a logoff:
First, add an event handler to Microsoft.Win32.SystemEvents.SessionEnded in the Service Constructor:
public MyService()
{
InitializeComponent;
Microsoft.Win32.SystemEvents.SessionEnded += new Microsoft.Win32.SessionEndedEventHandler(SystemEvents_SessionEnded);
}
Then add the handler:
void SystemEvents_SessionEnded(object sender, Microsoft.Win32.SessionEndedEventArgs e)
{
//your code here
}
This should catch any ended session, including the console itself (the one running the services).

Categories