From bedd49ce1704e6f3de237e7ac6382a54259fa2a8 Mon Sep 17 00:00:00 2001 From: Markus Ewald Date: Sat, 5 Jul 2025 21:05:55 +0200 Subject: [PATCH] Iterated a bit on the dialog view model design, it now uses the UI dispatcher to ensure the Close() method is invoked in the UI thread --- Source/AutoBinding/ConventionBinder.cs | 41 ++++++++++++++-------- Source/ViewModels/DialogResultEventArgs.cs | 6 ++-- Source/ViewModels/IDialogViewModel.cs | 6 ---- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/Source/AutoBinding/ConventionBinder.cs b/Source/AutoBinding/ConventionBinder.cs index 96364a0..674d1d2 100644 --- a/Source/AutoBinding/ConventionBinder.cs +++ b/Source/AutoBinding/ConventionBinder.cs @@ -62,25 +62,36 @@ namespace Nuclex.Avalonia.AutoBinding { if(dialogViewModel != null) { Window? viewAsWindow = view as Window; if(viewAsWindow != null) { - EventHandler handler = ( - delegate(object sender, DialogResultEventArgs arguments) { - viewAsWindow.Close(arguments.Result); - } - ); - - dialogViewModel.Submitted += handler; - - // Does this help anything? - // Without it, the view has a reference to the view model (via DataContext), - // and the view model references the view (via event subscription), but this - // shouldn't bother the .NET garbage collector at all. - viewAsWindow.Closed += delegate(object sender, EventArgs arguments) { - dialogViewModel.Submitted -= handler; - }; + bindViewModelSubmitToDialogClose(viewAsWindow, dialogViewModel); } } } + /// + /// Convention binding for view models with a 'Submit' event, + /// closes the dialog when the view model fires the event + /// + /// Window the displays the dialog's UI + /// View model that has the 'Submit' event + private static void bindViewModelSubmitToDialogClose( + Window dialogWindow, IDialogViewModel dialogViewModel + ) { + EventHandler handler = ( + delegate(object sender, DialogResultEventArgs arguments) { + dialogWindow.Close(arguments.Result); + } + ); + + dialogViewModel.Submitted += handler; + + // Does this help anything? + // Without it, the view has a reference to the view model (via DataContext), + // and the view model references the view (via event subscription), but this + // shouldn't bother the .NET garbage collector at all. + dialogWindow.Closed += delegate (object sender, EventArgs arguments) { + dialogViewModel.Submitted -= handler; + }; + } } } // namespace Nuclex.Avalonia.AutoBinding diff --git a/Source/ViewModels/DialogResultEventArgs.cs b/Source/ViewModels/DialogResultEventArgs.cs index 3ad3581..bc01d78 100644 --- a/Source/ViewModels/DialogResultEventArgs.cs +++ b/Source/ViewModels/DialogResultEventArgs.cs @@ -26,17 +26,17 @@ namespace Nuclex.Avalonia.ViewModels { /// Initializes a new dialog result event argument container /// Result the dialog should exit with - public DialogResultEventArgs(object result) { + public DialogResultEventArgs(object? result) { this.result = result; } /// Result that should be returned from the dialog - public object Result { + public object? Result { get { return this.result; } } /// Result that should be returned from the dialog - private readonly object result; + private readonly object? result; } diff --git a/Source/ViewModels/IDialogViewModel.cs b/Source/ViewModels/IDialogViewModel.cs index 4ec0690..8c446d8 100644 --- a/Source/ViewModels/IDialogViewModel.cs +++ b/Source/ViewModels/IDialogViewModel.cs @@ -18,7 +18,6 @@ limitations under the License. #endregion // Apache License 2.0 using System; -using System.Threading.Tasks; using Nuclex.Avalonia.ViewModels; @@ -30,11 +29,6 @@ namespace Nuclex.Avalonie.ViewModels { /// Indicates that the view should close event EventHandler Submitted; - /// Indicates that the dialog should be closed - /// Result the dialog should return - /// A task that finishes when the submit notification has been sent - Task SubmitAsync(object? dialogResult = null); - } } // namespace Nuclex.Avalonie.ViewModels