Skip to content

Commit

Permalink
feat: dialog consolidation
Browse files Browse the repository at this point in the history
  • Loading branch information
dansiegel committed Jun 13, 2023
1 parent 6d422f4 commit 42985c5
Show file tree
Hide file tree
Showing 28 changed files with 383 additions and 427 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Prism.Services.Dialogs
namespace Prism.Dialogs
{
/// <summary>
/// The result of the dialog.
Expand Down
179 changes: 154 additions & 25 deletions src/Prism.Core/Dialogs/DialogCallback.cs
Original file line number Diff line number Diff line change
@@ -1,57 +1,186 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;

namespace Prism.Dialogs;

public readonly struct DialogCallback
{
private MulticastDelegate _callback { get; }
private readonly bool _empty = false;
private readonly List<MulticastDelegate> _callbacks = new List<MulticastDelegate>();
private readonly List<MulticastDelegate> _errorCallbacks = new List<MulticastDelegate>();

[EditorBrowsable(EditorBrowsableState.Never)]
public DialogCallback(MulticastDelegate callback)
/// <summary>
/// Creates a new instance of a DialogCallback
/// </summary>
public DialogCallback()
: this(false)
{
_callback = callback;
}

private DialogCallback(bool empty) => _empty = empty;

[EditorBrowsable(EditorBrowsableState.Never)]
public Task Invoke(Exception ex) =>
Invoke(new DialogResult { Exception = ex });

[EditorBrowsable(EditorBrowsableState.Never)]
public async Task Invoke(IDialogResult result)
{
if (_callback is null)
if (_empty || (!_callbacks.Any() && !_errorCallbacks.Any()))
return;
else if (_callback is Action action)

if(result.Exception is not null)
{
// process error callbacks
if (_errorCallbacks.Any())
{
foreach(MulticastDelegate errorCallback in _errorCallbacks)
{
await Process(errorCallback, result);
}
return;
}
}


foreach(var callback in _callbacks)
{
await Process(callback, result);
}
}

private static async Task Process(MulticastDelegate @delegate, IDialogResult result)
{
if (@delegate is Action action)
action();
else if (_callback is Action<IDialogResult> actionResult)
else if (@delegate is Action<IDialogResult> actionResult)
actionResult(result);
else if (_callback is Action<Exception> actionError && result.Exception is not null)
actionError(result.Exception);
else if (_callback is Func<Task> func)
else if (@delegate is Action<Exception> actionException && result.Exception is not null)
actionException(result.Exception);
else if (@delegate is Func<Task> func)
await func();
else if (_callback is Func<IDialogResult, Task> funcResult)
else if (@delegate is Func<IDialogResult, Task> funcResult)
await funcResult(result);
else if(_callback is Func<Exception, Task> funcError && result.Exception is not null)
await funcError(result.Exception);
else if (@delegate is Func<Exception, Task> taskException && result.Exception is not null)
await taskException(result.Exception);
}

/// <summary>
/// Provides an empty DialogCallback that will not execute any
/// </summary>
public static DialogCallback Empty => new DialogCallback(true);

/// <summary>
/// Provides a delegate callback method when the Dialog is closed
/// </summary>
/// <param name="action">The callback</param>
/// <returns></returns>
public DialogCallback OnClose(Action action)
{
_callbacks.Add(action);
return this;
}


/// <summary>
/// Provides a delegate callback method when the Dialog is closed
/// </summary>
/// <param name="action">The callback</param>
/// <returns></returns>
public DialogCallback OnClose(Action<IDialogResult> action)
{
_callbacks.Add(action);
return this;
}

/// <summary>
/// Provides a delegate callback method when an Exception is encountered
/// </summary>
/// <param name="action">The callback</param>
/// <returns></returns>
public DialogCallback OnError(Action action)
{
_errorCallbacks.Add(action);
return this;
}

public static DialogCallback OnClose(Action action) =>
new (action);
/// <summary>
/// Provides a delegate callback method when an Exception is encountered
/// </summary>
/// <param name="action">The callback</param>
/// <returns></returns>
public DialogCallback OnError(Action<Exception> action)
{
_errorCallbacks.Add(action);
return this;
}

public static DialogCallback OnClose(Action<IDialogResult> action) =>
new (action);
/// <summary>
/// Provides a delegate callback method when an Exception is encountered
/// </summary>
/// <param name="action">The callback</param>
/// <returns></returns>
public DialogCallback OnError(Action<IDialogResult> action)
{
_errorCallbacks.Add(action);
return this;
}

public static DialogCallback OnError(Action<Exception> action) =>
new (action);
/// <summary>
/// Provides an asynchronous delegate callback method when the Dialog is closed
/// </summary>
/// <param name="func">The callback</param>
/// <returns></returns>
public DialogCallback OnCloseAsync(Func<Task> func)
{
_callbacks.Add(func);
return this;
}

public static DialogCallback OnCloseAsync(Func<Task> func) =>
new(func);
/// <summary>
/// Provides an asynchronous delegate callback method when the Dialog is closed
/// </summary>
/// <param name="func">The callback</param>
/// <returns></returns>
public DialogCallback OnCloseAsync(Func<IDialogResult, Task> func)
{
_callbacks.Add(func);
return this;
}

/// <summary>
/// Provides an asynchronous delegate callback method when an Exception is encountered
/// </summary>
/// <param name="func">The callback</param>
/// <returns></returns>
public DialogCallback OnErrorAsync(Func<Task> func)
{
_errorCallbacks.Add(func);
return this;
}

public static DialogCallback OnCloseAsync(Func<IDialogResult, Task> func) =>
new(func);
/// <summary>
/// Provides an asynchronous delegate callback method when an Exception is encountered
/// </summary>
/// <param name="func">The callback</param>
/// <returns></returns>
public DialogCallback OnErrorAsync(Func<Exception, Task> func)
{
_errorCallbacks.Add(func);
return this;
}

public static DialogCallback OnErrorAsync(Func<Exception, Task> func) =>
new(func);
/// <summary>
/// Provides an asynchronous delegate callback method when an Exception is encountered
/// </summary>
/// <param name="func">The callback</param>
/// <returns></returns>
public DialogCallback OnErrorAsync(Func<IDialogResult, Task> func)
{
_errorCallbacks.Add(func);
return this;
}
}
26 changes: 26 additions & 0 deletions src/Prism.Core/Dialogs/DialogResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,44 @@
#nullable enable
namespace Prism.Dialogs;

/// <summary>
/// An <see cref="IDialogResult"/> that contains <see cref="IDialogParameters"/> from the dialog
/// and the <see cref="ButtonResult"/> of the dialog.
/// </summary>
#if NET6_0_OR_GREATER
public record DialogResult : IDialogResult
{
/// <summary>
/// An <see cref="System.Exception"/> that was thrown by the DialogService
/// </summary>
public Exception? Exception { get; init; }

/// <summary>
/// The parameters from the dialog.
/// </summary>
public IDialogParameters Parameters { get; init; }

/// <summary>
/// The result of the dialog.
/// </summary>
public ButtonResult Result { get; init; } = ButtonResult.None;
}
#else
public class DialogResult : IDialogResult
{
/// <summary>
/// An <see cref="System.Exception"/> that was thrown by the DialogService
/// </summary>
public Exception? Exception { get; set; }

/// <summary>
/// The parameters from the dialog.
/// </summary>
public IDialogParameters Parameters { get; set; }

/// <summary>
/// The result of the dialog.
/// </summary>
public ButtonResult Result { get; private set; } = ButtonResult.None;
}
#endif
18 changes: 17 additions & 1 deletion src/Prism.Core/Dialogs/IDialogResult.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
using System;

#nullable enable
namespace Prism.Dialogs;

#nullable enable
/// <summary>
/// Contains <see cref="IDialogParameters"/> from the dialog
/// and the <see cref="ButtonResult"/> of the dialog.
/// </summary>
public interface IDialogResult
{
/// <summary>
/// An <see cref="System.Exception"/> that was thrown by the DialogService
/// </summary>
Exception? Exception { get; }

/// <summary>
/// The result of the dialog.
/// </summary>
public ButtonResult Result { get; }

/// <summary>
/// The parameters from the dialog.
/// </summary>
IDialogParameters Parameters { get; }
}
4 changes: 2 additions & 2 deletions src/Prism.Core/Dialogs/IDialogServiceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ public static void ShowDialog(this IDialogService dialogService, string name, Ac
dialogService.ShowDialog(name, null, callback);

public static void ShowDialog(this IDialogService dialogService, string name, IDialogParameters parameters, Action callback) =>
dialogService.ShowDialog(name, parameters, DialogCallback.OnClose(callback));
dialogService.ShowDialog(name, parameters, new DialogCallback().OnClose(callback));

public static void ShowDialog(this IDialogService dialogService, string name, IDialogParameters parameters, Action<IDialogResult> callback) =>
dialogService.ShowDialog(name, parameters, DialogCallback.OnClose(callback));
dialogService.ShowDialog(name, parameters, new DialogCallback().OnClose(callback));

public static Task<IDialogResult> ShowDialogAsync(this IDialogService dialogService, string name, IDialogParameters parameters)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
using System;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Prism.Common;
using Prism.Ioc;
using Windows.Foundation;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;

namespace Prism.Services.Dialogs
namespace Prism.Dialogs
{
public class DialogService : IDialogService
{
Expand All @@ -19,18 +15,10 @@ public DialogService(IContainerProvider containerProvider)
_containerProvider = containerProvider;
}

public void ShowDialog(string name, IDialogParameters parameters, Action<IDialogResult> callback)
{
ShowDialogInternal(name, parameters, callback);
}

public void ShowDialog(string name, IDialogParameters parameters, Action<IDialogResult> callback, string windowName)
{
ShowDialogInternal(name, parameters, callback, windowName);
}

void ShowDialogInternal(string name, IDialogParameters parameters, Action<IDialogResult> callback, string windowName = null)
public void ShowDialog(string name, IDialogParameters parameters, DialogCallback callback)
{
parameters ??= new DialogParameters();
var windowName = parameters.TryGetValue<string>(KnownDialogParameters.WindowName, out var wName) ? wName : null;
IDialogWindow contentDialog = CreateDialogWindow(windowName);
ConfigureDialogWindowEvents(contentDialog, callback);
ConfigureDialogWindowContent(name, contentDialog, parameters);
Expand Down Expand Up @@ -66,14 +54,14 @@ void ConfigureDialogWindowContent(string dialogName, IDialogWindow window, IDial
MvvmHelpers.ViewAndViewModelAction<IDialogAware>(viewModel, d => d.OnDialogOpened(parameters));
}

void ConfigureDialogWindowEvents(IDialogWindow contentDialog, Action<IDialogResult> callback)
void ConfigureDialogWindowEvents(IDialogWindow contentDialog, DialogCallback callback)
{
IDialogResult result = null;

Action<IDialogResult> requestCloseHandler = null;
requestCloseHandler = (o) =>
Action<IDialogParameters> requestCloseHandler = null;
requestCloseHandler = (p) =>
{
result = o;
result = new DialogResult { Parameters = p };
contentDialog.Hide();
};

Expand All @@ -84,7 +72,7 @@ void ConfigureDialogWindowEvents(IDialogWindow contentDialog, Action<IDialogResu
if (contentDialog.DataContext is IDialogAware dialogAware)
{
dialogAware.RequestClose += requestCloseHandler;
dialogAware.RequestClose = new DialogCloseEvent(requestCloseHandler);
}
};

Expand All @@ -104,22 +92,20 @@ void ConfigureDialogWindowEvents(IDialogWindow contentDialog, Action<IDialogResu
contentDialog.Closing += closingHandler;

TypedEventHandler<ContentDialog, ContentDialogClosedEventArgs> closedHandler = null;
closedHandler = (o, e) =>
closedHandler = async (o, e) =>
{
contentDialog.Closed -= closedHandler;
contentDialog.Closing -= closingHandler;
if (contentDialog.DataContext is IDialogAware dialogAware)
{
dialogAware.RequestClose -= requestCloseHandler;
dialogAware.OnDialogClosed();
}
if (result == null)
result = new DialogResult();
callback?.Invoke(result);
await callback.Invoke(result);
contentDialog.DataContext = null;
contentDialog.Content = null;
Expand Down
Loading

0 comments on commit 42985c5

Please sign in to comment.