[Refactor] Extract the logic of the ShowAsync() method from the Dialog.cs file to the DialogExtension.cs file.
This commit is contained in:
1 parent
19d6d1c289
commit
70d4a39e3b
2 files changed
+102
-57
No files matched your search
@@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using HandyControl.Interactivity;
|
||||
@@ -9,68 +6,19 @@ using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
public interface IDialogResult
|
||||
{
|
||||
object Result { get; set; }
|
||||
}
|
||||
|
||||
public class Dialog : ContentControl
|
||||
{
|
||||
private Adorner _container;
|
||||
|
||||
// It can not be replaced with the FrameworkElement.IsLoaded property, which will be false when the dialog just created.
|
||||
public bool IsClosed { get; private set; }
|
||||
|
||||
public Dialog()
|
||||
{
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Close, (s, e) => Close()));
|
||||
}
|
||||
|
||||
public static Task<TResult> ShowAsync<TView, TResult>() where TView : class, new() =>
|
||||
ShowAsync<TResult>(new TView());
|
||||
|
||||
public static Task<TResult> ShowAsync<TResult>(object content)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<TResult>();
|
||||
|
||||
var dialog = Show(content);
|
||||
dialog.Unloaded += OnUnloaded;
|
||||
|
||||
return tcs.Task;
|
||||
|
||||
void OnUnloaded(object sender, RoutedEventArgs args)
|
||||
{
|
||||
try
|
||||
{
|
||||
dialog.Unloaded -= OnUnloaded;
|
||||
tcs.SetResult(GetResult(dialog));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
tcs.SetException(e);
|
||||
}
|
||||
}
|
||||
|
||||
TResult GetResult(Dialog embeddedDialog)
|
||||
{
|
||||
if (!(embeddedDialog.Content is FrameworkElement frameworkElement))
|
||||
throw new InvalidOperationException("The dialog is not a derived class of the FrameworkElement. ");
|
||||
|
||||
if (!(frameworkElement.DataContext is IDialogResult dialogResult))
|
||||
throw new InvalidOperationException("The view model of the dialog is not implement the IDialogResult interface. ");
|
||||
|
||||
switch (dialogResult.Result)
|
||||
{
|
||||
case TResult result:
|
||||
return result;
|
||||
case null when !typeof(TResult).IsValueType:
|
||||
return default(TResult); // The default value of the value type may cause confusion, so should not help the user decide.
|
||||
default:
|
||||
throw new InvalidCastException("Could not cast " +
|
||||
$"the {(dialogResult.Result != null ? $"{dialogResult.Result.GetType()} type" : "null value")} " +
|
||||
$"to the {typeof(TResult)} type. ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Dialog Show<T>() where T : class, new() => Show(new T());
|
||||
public static Dialog Show<T>() where T : new() => Show(new T());
|
||||
|
||||
public static Dialog Show(object content)
|
||||
{
|
||||
@@ -97,6 +45,7 @@ namespace HandyControl.Controls
|
||||
Child = dialog
|
||||
};
|
||||
dialog._container = container;
|
||||
dialog.IsClosed = false;
|
||||
layer.Add(container);
|
||||
}
|
||||
}
|
||||
@@ -119,6 +68,7 @@ namespace HandyControl.Controls
|
||||
}
|
||||
var layer = decorator.AdornerLayer;
|
||||
layer?.Remove(_container);
|
||||
IsClosed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using HandyControl.Controls;
|
||||
|
||||
namespace HandyControl.Tools.Extension
|
||||
{
|
||||
public interface IDialogResultable
|
||||
{
|
||||
object Result { get; set; }
|
||||
|
||||
Action ClosureToken { get; set; }
|
||||
}
|
||||
|
||||
public static class DialogExtension
|
||||
{
|
||||
public static Task<TResult> GetResultAsync<TResult>(this Dialog @this)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<TResult>();
|
||||
|
||||
try
|
||||
{
|
||||
if (@this.IsClosed)
|
||||
{
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
@this.Unloaded += OnUnloaded;
|
||||
@this.GetViewModel<IDialogResultable>().ClosureToken = @this.Close;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
tcs.TrySetException(e);
|
||||
}
|
||||
|
||||
return tcs.Task;
|
||||
|
||||
// ReSharper disable once ImplicitlyCapturedClosure
|
||||
void OnUnloaded(object sender, RoutedEventArgs args)
|
||||
{
|
||||
@this.Unloaded -= OnUnloaded;
|
||||
SetResult();
|
||||
}
|
||||
|
||||
void SetResult()
|
||||
{
|
||||
try
|
||||
{
|
||||
tcs.TrySetResult(ExtractResult<TResult>(@this));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
tcs.TrySetException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Dialog Initialize<TViewModel>(this Dialog @this, Action<TViewModel> configure)
|
||||
{
|
||||
configure?.Invoke(@this.GetViewModel<TViewModel>());
|
||||
|
||||
return @this;
|
||||
}
|
||||
|
||||
public static TViewModel GetViewModel<TViewModel>(this Dialog @this)
|
||||
{
|
||||
if (!(@this.Content is FrameworkElement frameworkElement))
|
||||
throw new InvalidOperationException("The dialog is not a derived class of the FrameworkElement. ");
|
||||
|
||||
if (!(frameworkElement.DataContext is TViewModel viewModel))
|
||||
throw new InvalidOperationException($"The view model of the dialog is not the {typeof(TViewModel)} type or its derived class. ");
|
||||
|
||||
return viewModel;
|
||||
}
|
||||
|
||||
private static TResult ExtractResult<TResult>(Dialog dialog)
|
||||
{
|
||||
var viewModelResult = dialog.GetViewModel<IDialogResultable>().Result;
|
||||
|
||||
switch (viewModelResult)
|
||||
{
|
||||
case TResult result:
|
||||
return result;
|
||||
case null when !typeof(TResult).IsValueType:
|
||||
return default(TResult); // The default value of the value type may cause confusion, so should not help the user decide.
|
||||
default:
|
||||
throw new InvalidCastException("Could not cast " +
|
||||
$"the {(viewModelResult != null ? $"{viewModelResult.GetType()} type" : "null value")} " +
|
||||
$"to the {typeof(TResult)} type. ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user