简体   繁体   中英

Global exception handling in MVVM

Is there a way to implement a global exception handling with MVVM pattern. In my existing case, whenever an error is happening inside of ViewModel, the application does not crash, just "hides" the rest of bindings that happen after the code that caused the error (certainly this is very misleading for end user, and not true, and should never happen that way). I would not like to implement try catch for every operation in the viewModel, and I dont like the silent way of error exception, I would really love to implement a way for WPF app to handle global errors. Is there a way to do it with the MVVM?

After a long battle finally I have found a very easily way to implement handling exceptions inside of ViewModel. While creating a BindingListener that inherits from DefaultTraceListener is certainly a great way to find your binding errors during the debug mode, this will not catch exceptions that have occurred inside a ViewModel when running solution is standard mode. But AppDomain.CurrentDomain.FirstChanceException will.

App.xaml.cs:

AppDomain.CurrentDomain.FirstChanceException += new EventHandler<System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs>(CurrentDomain_FirstChanceException);


    private void CurrentDomain_FirstChanceException(object sender, FirstChanceExceptionEventArgs e)
    {
            Dispatcher.BeginInvoke(new Action(() => MessageBox.Show("Error Occurred \n\r" + e.Exception.Message + "\n\r" + e.Exception.StackTrace, "ERROR", MessageBoxButton.OK, MessageBoxImage.Error)));
    }

You could wrap each method in a lamba. Something like this...

        public async void DoSomething()
        {
            await RunSafe(async () =>
            {
                await model.DoSomething();
                await model.DoSomethingElse();
                await model.DoLastThing();
            });
        }
        private async Task RunSafe(Func<Task> del, [CallerMemberName] String methodName = "")
        {
            try
            {
                Log.Info("Executing {0}", methodName);
                await del();
            }
            catch (Exception ex)
            {
                StatusMessage = string.Format("Error in {0}(...): {1}\r\n{2}", methodName, ex.Message, ex.ToString());                

                Log.Error("Error occured in plug in.", ex);
            }
        }

Look into deriving the DefaultTraceListener class. I've seen people derive their own BindingListener from it, and override the WriteLine method to throw your own exceptions.

You can just spin one of these up during your application start, and it should go on it's own:

public class BindingListener : DefaultTraceListener`
{
    public BindingListener()
    {
        PresentationTraceSources.Refresh();
        PresentationTraceSources.DataBindingSource.Listeners.Add(this);SourceLevels.Error;
    }
    public override void WriteLine(string message){...}
}

Note: This may not do exactly what you want out of the box, you may have to modify a few props.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM