@@ -69,8 +69,8 @@ public static void Main(string[] args)
6969 } ) ;
7070
7171 if (
72- parseResult . Errors . Any (
73- x => x . Tag is ErrorType . HelpRequestedError or ErrorType . VersionRequestedError
72+ parseResult . Errors . Any ( x =>
73+ x . Tag is ErrorType . HelpRequestedError or ErrorType . VersionRequestedError
7474 )
7575 )
7676 {
@@ -172,7 +172,7 @@ internal static void SetupAvaloniaApp()
172172 {
173173 BaseCachePath = Path . Combine ( Path . GetTempPath ( ) , "StabilityMatrix" , "Cache" ) ,
174174 CacheDuration = TimeSpan . FromDays ( 1 ) ,
175- MaxMemoryCacheCount = 100
175+ MaxMemoryCacheCount = 100 ,
176176 }
177177 ) ;
178178 }
@@ -198,7 +198,7 @@ public static AppBuilder BuildAvaloniaApp()
198198 app = app . With (
199199 new Win32PlatformOptions
200200 {
201- RenderingMode = [ Win32RenderingMode . Wgl , Win32RenderingMode . Software ]
201+ RenderingMode = [ Win32RenderingMode . Wgl , Win32RenderingMode . Software ] ,
202202 }
203203 ) ;
204204 }
@@ -216,7 +216,7 @@ public static AppBuilder BuildAvaloniaApp()
216216 . With (
217217 new AvaloniaNativePlatformOptions
218218 {
219- RenderingMode = new [ ] { AvaloniaNativeRenderingMode . Software }
219+ RenderingMode = new [ ] { AvaloniaNativeRenderingMode . Software } ,
220220 }
221221 ) ;
222222 }
@@ -402,14 +402,28 @@ private static void CurrentDomain_UnhandledException(object sender, UnhandledExc
402402 if ( e . ExceptionObject is not Exception ex )
403403 return ;
404404
405+ ShowExceptionDialog ( ex , false ) ;
406+ }
407+
408+ internal static bool ShowExceptionDialog ( Exception ex , bool isRecoverable )
409+ {
405410 SentryId ? sentryId = null ;
406411
407412 // Exception automatically logged by Sentry if enabled
408413 if ( SentrySdk . IsEnabled )
409414 {
410- ex . SetSentryMechanism ( "AppDomain.UnhandledException" , handled : false ) ;
415+ ex . SetSentryMechanism (
416+ isRecoverable ? "Dispatcher.UnhandledException" : "AppDomain.UnhandledException" ,
417+ handled : isRecoverable
418+ ) ;
419+
411420 sentryId = SentrySdk . CaptureException ( ex ) ;
412- SentrySdk . FlushAsync ( ) . SafeFireAndForget ( ) ;
421+
422+ if ( ! isRecoverable )
423+ {
424+ SentrySdk . FlushAsync ( ) . SafeFireAndForget ( ) ;
425+ }
426+
413427 Logger . Warn ( ex , "Unhandled {Type}: {Message}" , ex . GetType ( ) . Name , ex . Message ) ;
414428 }
415429 else
@@ -419,11 +433,15 @@ private static void CurrentDomain_UnhandledException(object sender, UnhandledExc
419433
420434 if ( Application . Current ? . ApplicationLifetime is IClassicDesktopStyleApplicationLifetime lifetime )
421435 {
422- var dialog = new ExceptionDialog
436+ var viewModel = new ExceptionViewModel
423437 {
424- DataContext = new ExceptionViewModel { Exception = ex , SentryId = sentryId }
438+ Exception = ex ,
439+ SentryId = sentryId ,
440+ IsRecoverable = isRecoverable ,
425441 } ;
426442
443+ var dialog = new ExceptionDialog { DataContext = viewModel } ;
444+
427445 // We can only show dialog if main window exists, and is visible
428446 if ( lifetime . MainWindow is { PlatformImpl : not null , IsVisible : true } mainWindow )
429447 {
@@ -441,25 +459,38 @@ private static void CurrentDomain_UnhandledException(object sender, UnhandledExc
441459 _ =>
442460 {
443461 cts . Cancel ( ) ;
444- ExitWithException ( ex ) ;
462+ if ( ! isRecoverable || ! viewModel . IsContinueResult )
463+ {
464+ ExitWithException ( ex ) ;
465+ }
445466 } ,
446467 TaskScheduler . FromCurrentSynchronizationContext ( )
447468 ) ;
448469
449470 Dispatcher . UIThread . MainLoop ( cts . Token ) ;
471+ return viewModel . IsContinueResult ;
450472 }
451473 else
452474 {
453475 // No parent window available
454476 var cts = new CancellationTokenSource ( ) ;
455- // Exit on token cancellation
456- cts . Token . Register ( ( ) => ExitWithException ( ex ) ) ;
477+ // Exit on token cancellation only if not recoverable or user didn't choose continue
478+ cts . Token . Register ( ( ) =>
479+ {
480+ if ( ! isRecoverable || ! viewModel . IsContinueResult )
481+ {
482+ ExitWithException ( ex ) ;
483+ }
484+ } ) ;
457485
458486 dialog . ShowWithCts ( cts ) ;
459487
460488 Dispatcher . UIThread . MainLoop ( cts . Token ) ;
489+ return viewModel . IsContinueResult ;
461490 }
462491 }
492+
493+ return false ;
463494 }
464495
465496 [ DoesNotReturn ]
0 commit comments