I want that the WPF application starts only in certain conditions. I tried the following with no success:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
if (ConditionIsMet) // pseudo-code
{
base.OnStartup(e);
}
}
}
But the app runs normally even when the condition is not met
Try this:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
if (MyCondition)
{
ShowSomeDialog("Hey, I Can't start because...");
this.Shutdown();
}
}
Another solution
Designer
<Application x:Class="SingleInstanceWPF.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Startup="Application_Startup">
</Application>
Code behind
public partial class App : Application
{
private void Application_Startup(object sender, StartupEventArgs e)
{
if (ConditionIsMet)
{
var window = new MainWindow();
window.Show();
}
else
{
this.Shutdown();
}
}
}
It may be that I am doing this the really really hard way, but I have found that fighting with the invocation precedence/order on startup by assuming anything is futile. I really wanted any exception raised during the startup of the application to IMMEDIATELY bubble up to the outermost exception handler, but even when one was raised, my MVVM Locator object was automatically instantiating itself because it is defined as an application-level resource.
That meant that the chicken arrived before the egg but after the same egg had already broken!!!
So the solution was:
1) Remove MVVM Locator from App.xaml.
2) Create an Application_Startup event
Add these lines at the top:
#region Handlers For Unhandled Exceptions
// anything else to do on startup can go here and will fire after the base startup event of the application
// First make sure anything after this is handled
// Creates an instance of the class holding delegate methods that will handle unhandled exceptions.
CustomExceptionHandler eh = new CustomExceptionHandler();
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(eh.OnAppDomainException);
// this ensures that any unhandled exceptions bubble up to a messagebox at least
Dispatcher.CurrentDispatcher.UnhandledException += new DispatcherUnhandledExceptionEventHandler(eh.OnDispatcherUnhandledException);
#endregion Handlers For Unhandled Exceptions
3) Tie Startup to the Application_Startup event in App.xaml
e.g.
Startup="Application_Startup" <<<< this name is arbitrary but conventional AFAICT
4) In Applicaton_Startup, create the ViewModelLocator like this:
Resources.Add("Locator", new ViewModelLocator());
//You can use FindResource and an exception will be thrown straightaway as I recall
if (!(TryFindResource("Locator") == null))
throw new ResourceReferenceKeyNotFoundException("ViewModelLocator could not be created", "Locator");
5) Then, immediately after the resource has been found, open the MainWindow, but only if the Locator was successfully instantiated
Uri uri = new Uri("pack:Views/MainWindow.xaml", UriKind.RelativeOrAbsolute);
Application.Current.StartupUri = uri;
Step (4) will throw an exception immediately if the constructor on the Locator fails WHICH HAPPENS ALL THE TIME TO ME, REGRETTTABLY.
Then, the exception from step 4 is handled as follows (this example uses a RadMessageBox but feel free to fix that:
public void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
try
{
var result = this.ShowExceptionDialog(e.Exception);
}
catch
{
RadMessageBox.Show("Fatal Dispatcher Error - the application will now halt.", Properties.Resources.CaptionSysErrMsgDlg,
MessageBoxButton.OK, MessageBoxImage.Stop, true);
}
finally
{
e.Handled = true;
// TERMINATE WITH AN ERROR CODE -1!
//Environment.Exit(-1);
}
}
Related
Lets take a simple WPF application with two Window classes. The MainWindow has a single control - button - which creates AnotherWindow instance. If an Exception happens after the creation before the main thread exits ButtonMethod scope, then the application remains running after the MainWindow is closed and disappeared.
A workaround for that is to set a new window's Owner property to the MainWindow object instance.
The app will also keeps running even without any exception throwing if there would be no w.Show() or w.Close() call after an instance of AnotherWindow is created.
Questions:
Where is such behaviour of WPF window threads is described?
What is the best practice for creating other windows with an exception possibility keeping in mind: set window's Owner, call window.Close() in some finally scope or something else?
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
try
{
ButtonMethod();
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
}
}
private void ButtonMethod()
{
Window w = new AnotherWindow();
// Uncomment the line below to fix freezing at the exit.
// w.Owner = this;
throw new Exception("Custom user exception!");
w.Show();
}
}
To open a new window on wpf you use this code:
private void Button_Click(object sender, RoutedEventArgs e)
{
SecondWindow w = new SecondWindow();
w.Show();
}
And if you wish to close the one you're on is:
This.close();
You don't need the code
throw new Exception("Custom user exception!");
Because you're just making an exception which you are catching anyways, you throw an exception (typically) when you want to debug your code or to see if it's catching the right type of exceptions. I hope I helped.
This question already has answers here:
Globally catch exceptions in a WPF application?
(7 answers)
Closed 6 years ago.
Sometimes, under not reproducible circumstances, my WPF application crashes without any message. The application simply close instantly.
Where is the best place to implement the global Try/Catch block. At least I have to implement a messagebox with: "Sorry for the inconvenience ..."
You can trap unhandled exceptions at different levels:
AppDomain.CurrentDomain.UnhandledException From all threads in the AppDomain.
Dispatcher.UnhandledException From a single specific UI dispatcher thread.
Application.Current.DispatcherUnhandledException From the main UI dispatcher thread in your WPF application.
TaskScheduler.UnobservedTaskException from within each AppDomain that uses a task scheduler for asynchronous operations.
You should consider what level you need to trap unhandled exceptions at.
Deciding between #2 and #3 depends upon whether you're using more than one WPF thread. This is quite an exotic situation and if you're unsure whether you are or not, then it's most likely that you're not.
You can handle the AppDomain.UnhandledException event
EDIT: actually, this event is probably more adequate: Application.DispatcherUnhandledException
A quick example of code for Application.Dispatcher.UnhandledException:
public App() {
this.Dispatcher.UnhandledException += OnDispatcherUnhandledException;
}
void OnDispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) {
string errorMessage = string.Format("An unhandled exception occurred: {0}", e.Exception.Message);
MessageBox.Show(errorMessage, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
// OR whatever you want like logging etc. MessageBox it's just example
// for quick debugging etc.
e.Handled = true;
}
I added this code in App.xaml.cs
I use the following code in my WPF apps to show a "Sorry for the inconvenience" dialog box whenever an unhandled exception occurs. It shows the exception message, and asks user whether they want to close the app or ignore the exception and continue (the latter case is convenient when a non-fatal exceptions occur and user can still normally continue to use the app).
In App.xaml add the Startup event handler:
<Application .... Startup="Application_Startup">
In App.xaml.cs code add Startup event handler function that will register the global application event handler:
using System.Windows.Threading;
private void Application_Startup(object sender, StartupEventArgs e)
{
// Global exception handling
Application.Current.DispatcherUnhandledException += new DispatcherUnhandledExceptionEventHandler(AppDispatcherUnhandledException);
}
void AppDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
\#if DEBUG // In debug mode do not custom-handle the exception, let Visual Studio handle it
e.Handled = false;
\#else
ShowUnhandledException(e);
\#endif
}
void ShowUnhandledException(DispatcherUnhandledExceptionEventArgs e)
{
e.Handled = true;
string errorMessage = string.Format("An application error occurred.\nPlease check whether your data is correct and repeat the action. If this error occurs again there seems to be a more serious malfunction in the application, and you better close it.\n\nError: {0}\n\nDo you want to continue?\n(if you click Yes you will continue with your work, if you click No the application will close)",
e.Exception.Message + (e.Exception.InnerException != null ? "\n" +
e.Exception.InnerException.Message : null));
if (MessageBox.Show(errorMessage, "Application Error", MessageBoxButton.YesNoCancel, MessageBoxImage.Error) == MessageBoxResult.No) {
if (MessageBox.Show("WARNING: The application will close. Any changes will not be saved!\nDo you really want to close it?", "Close the application!", MessageBoxButton.YesNoCancel, MessageBoxImage.Warning) == MessageBoxResult.Yes)
{
Application.Current.Shutdown();
}
}
Best answer is probably https://stackoverflow.com/a/1472562/601990.
Here is some code that shows how to use it:
App.xaml.cs
public sealed partial class App
{
protected override void OnStartup(StartupEventArgs e)
{
// setting up the Dependency Injection container
var resolver = ResolverFactory.Get();
// getting the ILogger or ILog interface
var logger = resolver.Resolve<ILogger>();
RegisterGlobalExceptionHandling(logger);
// Bootstrapping Dependency Injection
// injects ViewModel into MainWindow.xaml
// remember to remove the StartupUri attribute in App.xaml
var mainWindow = resolver.Resolve<Pages.MainWindow>();
mainWindow.Show();
}
private void RegisterGlobalExceptionHandling(ILogger log)
{
// this is the line you really want
AppDomain.CurrentDomain.UnhandledException +=
(sender, args) => CurrentDomainOnUnhandledException(args, log);
// optional: hooking up some more handlers
// remember that you need to hook up additional handlers when
// logging from other dispatchers, shedulers, or applications
Application.Dispatcher.UnhandledException +=
(sender, args) => DispatcherOnUnhandledException(args, log);
Application.Current.DispatcherUnhandledException +=
(sender, args) => CurrentOnDispatcherUnhandledException(args, log);
TaskScheduler.UnobservedTaskException +=
(sender, args) => TaskSchedulerOnUnobservedTaskException(args, log);
}
private static void TaskSchedulerOnUnobservedTaskException(UnobservedTaskExceptionEventArgs args, ILogger log)
{
log.Error(args.Exception, args.Exception.Message);
args.SetObserved();
}
private static void CurrentOnDispatcherUnhandledException(DispatcherUnhandledExceptionEventArgs args, ILogger log)
{
log.Error(args.Exception, args.Exception.Message);
// args.Handled = true;
}
private static void DispatcherOnUnhandledException(DispatcherUnhandledExceptionEventArgs args, ILogger log)
{
log.Error(args.Exception, args.Exception.Message);
// args.Handled = true;
}
private static void CurrentDomainOnUnhandledException(UnhandledExceptionEventArgs args, ILogger log)
{
var exception = args.ExceptionObject as Exception;
var terminatingMessage = args.IsTerminating ? " The application is terminating." : string.Empty;
var exceptionMessage = exception?.Message ?? "An unmanaged exception occured.";
var message = string.Concat(exceptionMessage, terminatingMessage);
log.Error(exception, message);
}
}
In addition to the posts above:
Application.Current.DispatcherUnhandledException
will not catch exceptions that are thrown from a thread other than the main thread. You have to catch those exceptions on the same thread they are thrown. But if you want to Handle them on your global exception handler you can pass it to the main thread:
System.Threading.Thread t = new System.Threading.Thread(() =>
{
try
{
...
//this exception will not be catched by
//Application.DispatcherUnhandledException
throw new Exception("huh..");
...
}
catch (Exception ex)
{
//But we can handle it in the throwing thread
//and pass it to the main thread wehre Application.
//DispatcherUnhandledException can handle it
System.Windows.Application.Current.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal,
new Action<Exception>((exc) =>
{
throw new Exception("Exception from another Thread", exc);
}), ex);
}
});
To supplement Thomas's answer, the Application class also has the DispatcherUnhandledException event that you can handle.
A complete solution is here
it's explained very nice with sample code. However, be careful that it does not close the application.Add the line
Application.Current.Shutdown();
to gracefully close the app.
As mentioned above
Application.Current.DispatcherUnhandledException will not catch
exceptions that are thrown from another thread then the main thread.
That actual depend on how the thread was created
One case that is not handled by Application.Current.DispatcherUnhandledException is System.Windows.Forms.Timer for which Application.ThreadException can be used to handle these
if you run Forms on other threads than the main thread you will need to set Application.ThreadException from each such thread
we're having an application on server instance and quite rarely, but we have out of memory exception (program is not leaking, just instance is quite small and it operates with quite big amounts of data).
That would be not a problem, as we monitor processes on that server instance and if some of the processes are not found in process list, alert email is sent.
Now the problem is with this:
That prevents process from disappearing from process list, so we don't get alert email about it's failure. Is it possible to disable this message, that if program fails on something we don't catch, it would close without user interaction?
Assuming Windows Forms, I typically do multiple steps to prevent this message box.
First, I connect several handlers in the Main function:
[STAThread]
private static void Main()
{
Application.ThreadException +=
application_ThreadException;
Application.SetUnhandledExceptionMode(
UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException +=
currentDomain_UnhandledException;
Application.Run(new MainForm());
}
Those handlers are being called when an otherwise unhandled exception occurs. I would define them something like:
private static void application_ThreadException(
object sender,
ThreadExceptionEventArgs e)
{
doHandleException(e.Exception);
}
private static void currentDomain_UnhandledException(
object sender,
UnhandledExceptionEventArgs e)
{
doHandleException(e.ExceptionObject as Exception);
}
The actual doHandleException function that is then called does the actual error handling. Usually this is logging the error and notifying the user, giving him the options to continue the application or quit it.
An example from a real-world application looks like:
private static void doHandleException(
Exception e)
{
try
{
Log.Instance.ErrorException(#"Exception.", e);
}
catch (Exception x)
{
Trace.WriteLine(string.Format(
#"Error during exception logging: '{0}'.", x.Message));
}
var form = Form.ActiveForm;
if (form == null)
{
MessageBox.Show(buildMessage(e),
"MyApp", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
MessageBox.Show(form, buildMessage(e),
"MyApp", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
With the helper function:
public static string buildMessage(Exception exception)
{
var result = new StringBuilder();
while (exception != null)
{
result.AppendLine(exception.Message);
result.AppendLine();
exception = exception.InnerException;
}
return result.ToString().Trim();
}
If you are using not Windows Forms but e.g. a Console application or WPF, some handlers are not present, while others are present instead.
The idea stays the same: Subscribe to event handlers that are being called if you have no try...catch around your code blocks.
Personally, I try to have as few of those try...catch blocks as possible (ideally none).
don't know if you can deactivate this - but I think you should not.
Find the bug/problem in your application and handle the problem with a craceful shutdown or by preventing the problem in first case.
Everything else will be a real crude workaround and I don't think your client will be pleased to have such a behavior (after all won't there be data lost? If not this has allways the buggy / not finished touch)
You could put a global try/catch block in your program and exit the program on any unexpected exception.
If using WPF you can try-catch the following two exceptions in your app.xaml.cs. There may be other/complementary exceptions to handle, but this are the two I am usually looking for:
AppDomain.CurrentDomain.UnhandledException - "This event provides notification of uncaught exceptions. It allows the application to log information about the exception before the system default handler reports the exception to the user and terminates the application. If sufficient information about the state of the application is available, other actions may be undertaken — such as saving program data for later recovery. Caution is advised, because program data can become corrupted when exceptions are not handled."
Dispatcher.UnhandledException - "Occurs when a thread exception is thrown and uncaught during execution of a delegate by way of Invoke or BeginInvoke."
ie:
public partial class App : Application
{
public App()
{
this.Dispatcher.UnhandledException += DispatcherUnhandledException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomainUnhandledException;
}
private void CurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
// log and close gracefully
}
private new void DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
e.Handled = true;
// log and close gracefully
}
}
For some reason I can't get this to work at all. I have read from various sources that I can override OnStartup in a WPF application and it will fire off as the App is created. However, no matter what I do, nothing is happening. Here is the code.
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
// My code goes here, but nothing ever happens.
base.OnStartup(e);
}
}
Obviously I am missing something. Sadly the MSDN page doesn't offer much insight either.
http://msdn.microsoft.com/en-us/library/system.windows.application.onstartup.aspx
What am I doing wrong?
EDIT:
It turns out that my problem was a small typo in the namespace. App.xaml.cs had the class defined as 'RTDMyApp.App' and the App.xaml file was referring to it as 'RTD_MYApp.App' At any rate, this fact, combined with the accepted answer below has gotten me back on track.
Did you remove the StartupUri too from the App xaml?
If you did you have to create the window you want show:
base.OnStartUp(e);
var window = new Window1();
this.MainWindow = window;
window.Show();
I think what you really want to do is to subscribe to the Startup event. You can do this in your XAML file:
<Application ... Startup="Application_Startup">
Sequence sequence sequence. How annoying.
The right sequence (for a WPF application with NO Main method explicitly developed/declared) is:
// XAML
... Startup="Application_Startup"
//code-behind
private void Application_Startup(object sender, StartupEventArgs e)
{
...
...
// do something. In fact, here I do a lot of stuff that reflects
// some serious recent application illnesss:
try
{
//http://connect.microsoft.com/VisualStudio/feedback/details/618027/uriformatexception-thrown-by-ms-internal-fontcache-util
System.Environment.SetEnvironmentVariable("windir", Environment.GetEnvironmentVariable("SystemRoot"));
// per http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo.ietflanguagetag(v=vs.110).aspx
var cultureName = CultureInfo.CurrentCulture.Name;
FrameworkElement.LanguageProperty.OverrideMetadata(
typeof(FrameworkElement),
new FrameworkPropertyMetadata(
XmlLanguage.GetLanguage(cultureName)));
// Setup unhandled exception handlers
#region Handlers For Unhandled Exceptions
// anything else to do on startup can go here and will fire after the base startup event of the application
// First make sure anything after this is handled
// Creates an instance of the class holding delegate methods that will handle unhandled exceptions.
CustomExceptionHandler eh = new CustomExceptionHandler();
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(eh.OnAppDomainException);
// this ensures that any unhandled exceptions bubble up to a messagebox at least
Dispatcher.CurrentDispatcher.UnhandledException += new DispatcherUnhandledExceptionEventHandler(eh.OnDispatcherUnhandledException);
#endregion Handlers For Unhandled Exceptions
// Start the dispatcher
// for Galasoft threading and messaging
DispatcherHelper.Initialize();
}
catch (Exception ex)
{
ex.PreserveExceptionDetail();
throw ex;
}
}
and then I do:
protected override void OnStartup(StartupEventArgs e)
{
App.Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
App.HasRaisedFatalException = false;
base.OnStartup(e);
try
{
//Force just one copy to run
this.ForceSingleInstance();
...
...
...
}
and so far the patient is feeling much better.
I am currently writing a WPF application which does command-line argument handling in App.xaml.cs (which is necessary because the Startup event seems to be the recommended way of getting at those arguments). Based on the arguments I want to exit the program at that point already which, as far as I know, should be done in WPF with Application.Current.Shutdown() or in this case (as I am in the current application object) probably also just this.Shutdown().
The only problem is that this doesn't seem to work right. I've stepped through with the debugger and code after the Shutdown() line still gets executed which leads to errors afterwards in the method, since I expected the application not to live that long. Also the main window (declared in the StartupUri attribute in XAML) still gets loaded.
I've checked the documentation of that method and found nothing in the remarks that tell me that I shouldn't use it during Application.Startup or Application at all.
So, what is the right way to exit the program at that point, i. e. the Startup event handler in an Application object?
First remove the StartupUri property from App.xaml and then use the following:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
bool doShutDown = ...;
if (doShutDown)
{
Shutdown(1);
return;
}
else
{
this.StartupUri = new Uri("Window1.xaml", UriKind.Relative);
}
}
If you remove the StartupUri from app.xaml for an application with a MainWindow you need to make sure you make the following call in your OnStartup method otherwise the application will not terminate when your MainWindow closes.
this.ShutdownMode = System.Windows.ShutdownMode.OnMainWindowClose;
#Frank Schwieterman, something along these lines may help you with your console window issue.
I did this a little differently to avoid having to set the StartupUri and ShutdownMode properties. First edit the App.xaml file and replace StartupUri with Startup:
<Application x:Class="Menu.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Menu"
Startup="Application_Startup">
<Application.Resources>
</Application.Resources>
</Application>
Then add Application_Startup to the code along with OnExit:
public partial class App : Application
{
private volatile static Mutex s_mutex;
private void Application_Startup(object sender, StartupEventArgs e)
{
s_mutex = new Mutex(true, #"Global\MenuMutex", out bool grantedOwnership);
if (!grantedOwnership)
{
MessageBox.Show($"Another instance is already running!", "Error", MessageBoxButton.OK, MessageBoxImage.Exclamation);
Current.Shutdown();
}
else
new MainWindow().Show();
}
protected override void OnExit(ExitEventArgs e)
{
s_mutex?.ReleaseMutex();
s_mutex?.Dispose();
s_mutex = null;
base.OnExit(e);
}
Write in the Application_Startup:
private void Application_Startup(object sender, StartupEventArgs e)
{
...
if (!condition)
{
e.GetType()
.GetProperty("PerformDefaultAction", BindingFlags.Instance | BindingFlags.NonPublic)
.SetValue(e, false);
Shutdown();
return;
}
...
}