trapping the event when a messagebox is closed and using as delegate - c#

The following works fine for a windows form.
It simply uses a delegate to reactivate a GroupBorder on the parent form when the child form is closed.
private void uxUpdateDataButton_Click(object sender, EventArgs e)
{
uxRevisionHelperGroupBox.Enabled = false;
uxBindingNavigator.Hide();
uxFormDatabase myNewDisplay = new uxFormDatabase();
myNewDisplay.FormClosed += delegate { activateGroupBorder(); };
myNewDisplay.Show();
}
public void activateGroupBorder()
{
uxRevisionHelperGroupBox.Enabled = true;
uxBindingNavigator.Show();
}
Is it possible to do the equivalent to the above but for a messagebox instead of the child form?
This is my attempt which is not the solution:
private void uxAuthorPictureBox_Click(object sender, EventArgs e)
{
uxRevisionHelperGroupBox.Enabled = false;
uxBindingNavigator.Hide();
MessageBox myMessage = new MessageBox;
myMessage.close += delegate { activateGroupBorder(); };
myMessage.Show("hello world");
}
public void activateGroupBorder()
{
uxRevisionHelperGroupBox.Enabled = true;
uxBindingNavigator.Show();
}

MessageBox.Show(...) is synchronous call, i.e. execution doesn't continue further until box is closed. Why can't you just call your activateGroupBorder() after the message box is done? E.g.:
MessageBox.Show("hello world");
this.activateGroupBorder();

Related

How to run different timer inside a timer without pausing the GUI?

I have a class SendCountingInfo() and it will send a message to server every 5 minutes. The code inside this class are:
public void StartSendCountingInfo()
{
DoStartSendCountingInfo(300000);
}
private void DoStartSendCountingInfo(int iMiSecs)
{
_pingTimer = new System.Timers.Timer(iMiSecs);
_pingTimer.Elapsed += new System.Timers.ElapsedEventHandler(pingTimer_Elapsed);
_pingTimer.Start();
}
void pingTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
PingRemoteHost();
}
When I try to call it in the Windows Form class, it didn't work.
But, when I remove the timer and call PingRemoteHost() directly, it works. However, the form didn't load properly. It shows blank screen but the method PingRemoteHost() work.
Here is the code inside the windows form:
private void Layout_Load(object sender, EventArgs e)
{
tSystemChecker = new System.Timers.Timer(1000);
tSystemChecker.Elapsed += new System.Timers.ElapsedEventHandler(tSystemChecker_Elapsed);
tSystemChecker.Start();
this.WindowState = FormWindowState.Maximized;
}
void tSystemChecker_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
UIThreadWork(this, delegate
{
try
{
SuspendLayout();
DoCheckHardwareStatus();
DoCheckLanguage();
SendCountingInfo sci = new SendCountingInfo();
sci.StartSendCountingInfo();
}
catch (Exception exp)
{
System.Diagnostics.Debug.WriteLine(exp.Message);
System.Diagnostics.Debug.WriteLine(exp.Source);
System.Diagnostics.Debug.WriteLine(exp.StackTrace);
}
ResumeLayout(true);
});
}
Do you have any idea what's wrong?
Use a thread and see if the problem persist
using System.Threading;
//Put this where you want to start the first timer
Thread thread = new Thread(dowork =>
{
public void StartSendCountingInfo();
}
If you are updating the GUI use for your controls
guicontrol.BeginInvoke((MethodInvoker)delegate()
{
guicontrol.Text = "aa";
//etc
});

Trying to showing a dialog on DispatcherUnhandledException

I have a WPF application into which I'm adding some top level, catch all error handling. I handle the DispatcherUnhandledException event like so:
private void App_OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
if (_isHandlingError)
{
_log.Error("Critical unhandled error", e.Exception);
e.Handled = true;
return;
}
_isHandlingError = true;
var vm = _windsorContainer.Resolve<ErrorReporterViewModel>();
Dispatcher.Invoke(() =>
{
vm.Details = FailureMessageBuilder.CreateContent(e.Exception);
var view = new ErrorReporterView { DataContext = vm };
view.Show();
});
e.Handled = true;
NotifyOfException(e.Exception, vm.Description);
_isHandlingError = false;
}
The problem is, that the call to Show() (or ShowDialog) never returns, and the error dialog is never shown.
What might be the issue?
Do you have attached your event to the Application?
cApp.Dispatcher.UnhandledException += new DispatcherUnhandledExceptionEventHandler(Dispatcher_UnhandledException);
cApp.InitializeComponent();
cApp.Run(new MainWindow());
And then
private static void Dispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
...e.Exception.Message
}

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();
};

Why is a disabled button clickable?

This case is using C# WPF. I want to instantly disable a button after clicking it to prevent clicking it twice in short succession. I disabled the button in OnClick_Event but still clickable.
Part of source is as below.
private void Button_Click_UpdateBurndownChart(object sender, RoutedEventArgs e)
{
if(threadNotWorking)
{
updateButton.IsEnabled = false;
startWorkThread();
}
}
private void startWorkThread()
{
... ...
//after finish required process
updateButton.IsEnabled = true;
}
Is there any way to accomplish this?
you may want to use a dispatcher, there is probably a threading problem (callback function running on seperate thread and trying to access ui which runs on another thread). try this . .
updateButton.Dispatcher.BeginInvoke(
new ThreadStart(() => updateButton.IsEnabled = false),
System.Windows.Threading.DispatcherPriority.Input, null);
instead of
updateButton.IsEnabled = false;
What happens if you were instead to change the order of your events from:
updateButton.IsEnabled = false;
startWorkThread();
To
startWorkThread();
updateButton.IsEnabled = false;
Let me know how this goes.
What it looks like is that you are starting your thread then immediatly enabling your button before your thread has finished. You would be better off using a BackgroundWorker and enable your Button in the RunWorkerCompleted Event. Though you can do something similar by enabling your button using a BeginInvoke at the end of your Process.
public void doWork()
{
System.Threading.Thread.Sleep(10000); //Simulating your Process
Dispatcher.BeginInvoke(new System.Threading.ThreadStart(delegate() { updateButton.IsEnabled = true; }), System.Windows.Threading.DispatcherPriority.Background);
}
Example with BackgroundWorker
using System.ComponentModel;
public partial class MainWindow : Window
{
BackgroundWorker bgw;
public MainWindow()
{
InitializeComponent();
bgw = new BackgroundWorker();
bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted);
}
void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
updateButton.IsEnabled = true;
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
System.Threading.Thread.Sleep(10000); //Simulating your work
}
private void startWorkThread()
{
bgw.RunWorkerAsync();
}
private void updateButton_Click(object sender, RoutedEventArgs e)
{
if (bgw.IsBusy != true)
{
updateButton.IsEnabled = false;
startWorkThread();
}
}
}

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