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

This commit is contained in:
Markus Ewald 2025-07-05 21:05:55 +02:00
parent e11922ae4f
commit bedd49ce17
3 changed files with 29 additions and 24 deletions

View File

@ -62,9 +62,23 @@ namespace Nuclex.Avalonia.AutoBinding {
if(dialogViewModel != null) { if(dialogViewModel != null) {
Window? viewAsWindow = view as Window; Window? viewAsWindow = view as Window;
if(viewAsWindow != null) { if(viewAsWindow != null) {
bindViewModelSubmitToDialogClose(viewAsWindow, dialogViewModel);
}
}
}
/// <summary>
/// Convention binding for view models with a 'Submit' event,
/// closes the dialog when the view model fires the event
/// </summary>
/// <param name="dialogWindow">Window the displays the dialog's UI</param>
/// <param name="dialogViewModel">View model that has the 'Submit' event</param>
private static void bindViewModelSubmitToDialogClose(
Window dialogWindow, IDialogViewModel dialogViewModel
) {
EventHandler<DialogResultEventArgs> handler = ( EventHandler<DialogResultEventArgs> handler = (
delegate(object sender, DialogResultEventArgs arguments) { delegate(object sender, DialogResultEventArgs arguments) {
viewAsWindow.Close(arguments.Result); dialogWindow.Close(arguments.Result);
} }
); );
@ -74,13 +88,10 @@ namespace Nuclex.Avalonia.AutoBinding {
// Without it, the view has a reference to the view model (via DataContext), // 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 // and the view model references the view (via event subscription), but this
// shouldn't bother the .NET garbage collector at all. // shouldn't bother the .NET garbage collector at all.
viewAsWindow.Closed += delegate(object sender, EventArgs arguments) { dialogWindow.Closed += delegate (object sender, EventArgs arguments) {
dialogViewModel.Submitted -= handler; dialogViewModel.Submitted -= handler;
}; };
} }
} }
}
}
} // namespace Nuclex.Avalonia.AutoBinding } // namespace Nuclex.Avalonia.AutoBinding

View File

@ -26,17 +26,17 @@ namespace Nuclex.Avalonia.ViewModels {
/// <summary>Initializes a new dialog result event argument container</summary> /// <summary>Initializes a new dialog result event argument container</summary>
/// <param name="result">Result the dialog should exit with</param> /// <param name="result">Result the dialog should exit with</param>
public DialogResultEventArgs(object result) { public DialogResultEventArgs(object? result) {
this.result = result; this.result = result;
} }
/// <summary>Result that should be returned from the dialog</summary> /// <summary>Result that should be returned from the dialog</summary>
public object Result { public object? Result {
get { return this.result; } get { return this.result; }
} }
/// <summary>Result that should be returned from the dialog</summary> /// <summary>Result that should be returned from the dialog</summary>
private readonly object result; private readonly object? result;
} }

View File

@ -18,7 +18,6 @@ limitations under the License.
#endregion // Apache License 2.0 #endregion // Apache License 2.0
using System; using System;
using System.Threading.Tasks;
using Nuclex.Avalonia.ViewModels; using Nuclex.Avalonia.ViewModels;
@ -30,11 +29,6 @@ namespace Nuclex.Avalonie.ViewModels {
/// <summary>Indicates that the view should close</summary> /// <summary>Indicates that the view should close</summary>
event EventHandler<DialogResultEventArgs> Submitted; event EventHandler<DialogResultEventArgs> Submitted;
/// <summary>Indicates that the dialog should be closed</summary>
/// <param name="dialogResult">Result the dialog should return</param>
/// <returns>A task that finishes when the submit notification has been sent</returns>
Task SubmitAsync(object? dialogResult = null);
} }
} // namespace Nuclex.Avalonie.ViewModels } // namespace Nuclex.Avalonie.ViewModels