feat: refactor OverlayDialog and add options.

This commit is contained in:
rabbitism
2024-02-02 00:01:18 +08:00
parent fb11be0169
commit 8f4d88b87f
8 changed files with 280 additions and 58 deletions

View File

@@ -45,6 +45,6 @@ public partial class DialogWithActionViewModel: ObservableObject, IDialogContext
private async Task ShowDialog() private async Task ShowDialog()
{ {
await OverlayDialog.ShowCustomModalAsync<DialogWithAction, DialogWithActionViewModel, bool>(new DialogWithActionViewModel()); await OverlayDialog.ShowCustomModal<DialogWithAction, DialogWithActionViewModel, bool>(new DialogWithActionViewModel());
} }
} }

View File

@@ -103,12 +103,15 @@ public class DialogDemoViewModel: ObservableObject
{ {
if (IsModal) if (IsModal)
{ {
DefaultResult = await OverlayDialog.ShowModalAsync<PlainDialog, PlainDialogViewModel>( DefaultResult = await OverlayDialog.ShowModal<PlainDialog, PlainDialogViewModel>(
vm, vm,
IsGlobal ? null : "LocalHost", IsGlobal ? null : "LocalHost",
"Please select a date", new OverlayDialogOptions()
SelectedMode, {
SelectedButton Title = "Please select a date",
Mode = SelectedMode,
Buttons = SelectedButton
}
); );
Date = vm.Date; Date = vm.Date;
} }
@@ -117,9 +120,12 @@ public class DialogDemoViewModel: ObservableObject
OverlayDialog.Show<PlainDialog, PlainDialogViewModel>( OverlayDialog.Show<PlainDialog, PlainDialogViewModel>(
new PlainDialogViewModel(), new PlainDialogViewModel(),
IsGlobal ? null : "LocalHost", IsGlobal ? null : "LocalHost",
"Please select a date", new OverlayDialogOptions()
SelectedMode, {
SelectedButton); Title = "Please select a date",
Mode = SelectedMode,
Buttons = SelectedButton
});
} }
} }
@@ -148,7 +154,7 @@ public class DialogDemoViewModel: ObservableObject
{ {
if (IsModal) if (IsModal)
{ {
Result = await OverlayDialog.ShowCustomModalAsync<DialogWithAction, DialogWithActionViewModel, bool>( Result = await OverlayDialog.ShowCustomModal<DialogWithAction, DialogWithActionViewModel, bool>(
vm, IsGlobal ? null : "LocalHost"); vm, IsGlobal ? null : "LocalHost");
Date = vm.Date; Date = vm.Date;
} }

View File

@@ -38,6 +38,13 @@ public static class Dialog
} }
} }
/// <summary>
/// Show a Window Dialog that with all content fully customized. And the owner of the dialog is specified.
/// </summary>
/// <param name="view">View to show in Dialog Window</param>
/// <param name="vm">ViewModel</param>
/// <param name="owner">Owner Window</param>
/// <param name="options">Dialog options to configure the window. </param>
public static void ShowCustom(Control view, object? vm, Window? owner = null, DialogOptions? options = null) public static void ShowCustom(Control view, object? vm, Window? owner = null, DialogOptions? options = null)
{ {
var window = new DialogWindow var window = new DialogWindow
@@ -57,6 +64,15 @@ public static class Dialog
} }
} }
/// <summary>
/// Show a Modal Dialog Window with default style.
/// </summary>
/// <param name="vm"></param>
/// <param name="owner"></param>
/// <param name="options"></param>
/// <typeparam name="TView"></typeparam>
/// <typeparam name="TViewModel"></typeparam>
/// <returns></returns>
public static Task<DialogResult> ShowModal<TView, TViewModel>(TViewModel vm, Window? owner = null, public static Task<DialogResult> ShowModal<TView, TViewModel>(TViewModel vm, Window? owner = null,
DialogOptions? options = null) DialogOptions? options = null)
where TView: Control, new() where TView: Control, new()
@@ -76,6 +92,14 @@ public static class Dialog
return window.ShowDialog<DialogResult>(owner); return window.ShowDialog<DialogResult>(owner);
} }
/// <summary>
/// Show a Modal Dialog Window with default style.
/// </summary>
/// <param name="view"></param>
/// <param name="vm"></param>
/// <param name="owner"></param>
/// <param name="options"></param>
/// <returns></returns>
public static Task<DialogResult> ShowModal(Control view, object? vm, Window? owner = null, DialogOptions? options = null) public static Task<DialogResult> ShowModal(Control view, object? vm, Window? owner = null, DialogOptions? options = null)
{ {
var window = new DefaultDialogWindow var window = new DefaultDialogWindow
@@ -93,6 +117,16 @@ public static class Dialog
return window.ShowDialog<DialogResult>(owner); return window.ShowDialog<DialogResult>(owner);
} }
/// <summary>
/// Show a Modal Dialog Window with all content fully customized.
/// </summary>
/// <param name="vm"></param>
/// <param name="owner"></param>
/// <param name="options"></param>
/// <typeparam name="TView"></typeparam>
/// <typeparam name="TViewModel"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
public static Task<TResult?> ShowCustomModal<TView, TViewModel, TResult>(TViewModel vm, Window? owner = null, public static Task<TResult?> ShowCustomModal<TView, TViewModel, TResult>(TViewModel vm, Window? owner = null,
DialogOptions? options = null) DialogOptions? options = null)
where TView: Control, new() where TView: Control, new()
@@ -112,6 +146,15 @@ public static class Dialog
return window.ShowDialog<TResult?>(owner); return window.ShowDialog<TResult?>(owner);
} }
/// <summary>
/// Show a Modal Dialog Window with all content fully customized.
/// </summary>
/// <param name="view"></param>
/// <param name="vm"></param>
/// <param name="owner"></param>
/// <param name="options"></param>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
public static Task<TResult?> ShowCustomModal<TResult>(Control view, object? vm, Window? owner = null, public static Task<TResult?> ShowCustomModal<TResult>(Control view, object? vm, Window? owner = null,
DialogOptions? options = null) DialogOptions? options = null)
{ {
@@ -130,12 +173,21 @@ public static class Dialog
return window.ShowDialog<TResult?>(owner); return window.ShowDialog<TResult?>(owner);
} }
/// <summary>
/// Get the main window of the application as default owner of the dialog.
/// </summary>
/// <returns></returns>
private static Window? GetMainWindow() private static Window? GetMainWindow()
{ {
var lifetime = Application.Current?.ApplicationLifetime; var lifetime = Application.Current?.ApplicationLifetime;
return lifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } w } ? w : null; return lifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } w } ? w : null;
} }
/// <summary>
/// Attach options to dialog window.
/// </summary>
/// <param name="window"></param>
/// <param name="options"></param>
private static void AssignOptionsToDialogWindow(DialogWindow window, DialogOptions? options) private static void AssignOptionsToDialogWindow(DialogWindow window, DialogOptions? options)
{ {
if (options is null) if (options is null)
@@ -157,6 +209,11 @@ public static class Dialog
} }
} }
/// <summary>
/// Attach options to default dialog window.
/// </summary>
/// <param name="window"></param>
/// <param name="options"></param>
private static void AssignOptionsToDefaultDialogWindow(DefaultDialogWindow window, DialogOptions? options) private static void AssignOptionsToDefaultDialogWindow(DefaultDialogWindow window, DialogOptions? options)
{ {
if (options is null) if (options is null)
@@ -179,6 +236,4 @@ public static class Dialog
} }
} }
} }
} }

View File

@@ -19,6 +19,13 @@ public class DialogControl: ContentControl
protected internal Button? _closeButton; protected internal Button? _closeButton;
private Panel? _titleArea; private Panel? _titleArea;
internal HorizontalPosition HorizontalAnchor { get; set; }
internal VerticalPosition VerticalAnchor { get; set; }
internal double? InitialHorizontalOffset { get; set; }
internal double? InitialVerticalOffset { get; set; }
internal bool CanClickOnMaskToClose { get; set; }
public event EventHandler<DialogLayerChangeEventArgs>? LayerChanged; public event EventHandler<DialogLayerChangeEventArgs>? LayerChanged;
public event EventHandler<object?>? DialogControlClosing; public event EventHandler<object?>? DialogControlClosing;

View File

@@ -25,8 +25,3 @@ public class DialogOptions
public DialogButton Button { get; set; } = DialogButton.OKCancel; public DialogButton Button { get; set; } = DialogButton.OKCancel;
} }
public class OverlayDialogOptions
{
public bool ClickOnMaskToClose { get; set; } = false;
}

View File

@@ -5,72 +5,188 @@ namespace Ursa.Controls;
public static class OverlayDialog public static class OverlayDialog
{ {
public static Task<DialogResult> ShowModalAsync<TView, TViewModel>( public static void Show<TView, TViewModel>(TViewModel vm, string? hostId = null,
TViewModel vm, OverlayDialogOptions? options = null)
string? hostId = null,
string? title = null,
DialogMode mode = DialogMode.None,
DialogButton buttons = DialogButton.OKCancel)
where TView : Control, new() where TView : Control, new()
{ {
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return;
var t = new DefaultDialogControl() var t = new DefaultDialogControl()
{ {
Content = new TView(){ DataContext = vm }, Content = new TView(){ DataContext = vm },
DataContext = vm, DataContext = vm,
Buttons = buttons,
Title = title,
Mode = mode,
}; };
ConfigureDefaultDialogControl(t, options);
host?.AddDialog(t);
}
public static void Show(Control control, object? vm, string? hostId = null,
OverlayDialogOptions? options = null)
{
var host = OverlayDialogManager.GetHost(hostId); var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return;
var t = new DefaultDialogControl()
{
Content = control,
DataContext = vm,
};
ConfigureDefaultDialogControl(t, options);
host?.AddDialog(t);
}
public static void Show(object? vm, string? hostId = null, OverlayDialogOptions? options = null)
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return;
var view = host.GetDataTemplate(vm)?.Build(vm);
if (view is null) view = new ContentControl();
view.DataContext = vm;
var t = new DefaultDialogControl()
{
Content = view,
DataContext = vm,
};
ConfigureDefaultDialogControl(t, options);
host.AddDialog(t);
}
public static void ShowCustom<TView, TViewModel>(TViewModel vm, string? hostId = null,
OverlayDialogOptions? options = null)
where TView: Control, new()
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return;
var t = new DialogControl()
{
Content = new TView(),
DataContext = vm,
};
ConfigureDialogControl(t, options);
host?.AddDialog(t);
}
public static void ShowCustom(Control control, object? vm, string? hostId = null,
OverlayDialogOptions? options = null)
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return;
var t = new DialogControl()
{
Content = control,
DataContext = vm,
};
ConfigureDialogControl(t, options);
host?.AddDialog(t);
}
public static void ShowCustom(object? vm, string? hostId = null,
OverlayDialogOptions? options = null)
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return;
var view = host.GetDataTemplate(vm)?.Build(vm);
if (view is null) view = new ContentControl();
view.DataContext = vm;
var t = new DialogControl()
{
Content = view,
DataContext = vm,
};
ConfigureDialogControl(t, options);
host.AddDialog(t);
}
public static Task<DialogResult> ShowModal<TView, TViewModel>(TViewModel vm, string? hostId = null,
OverlayDialogOptions? options = null)
where TView: Control, new()
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return Task.FromResult(DialogResult.None);
var t = new DefaultDialogControl()
{
Content = new TView(),
DataContext = vm,
};
ConfigureDefaultDialogControl(t, options);
host?.AddModalDialog(t); host?.AddModalDialog(t);
return t.ShowAsync<DialogResult>(); return t.ShowAsync<DialogResult>();
} }
public static Task<TResult> ShowCustomModalAsync<TView, TViewModel, TResult>( public static Task<DialogResult> ShowModal(Control control, object? vm, string? hostId = null,
TViewModel vm, OverlayDialogOptions? options = null)
string? hostId = null)
where TView: Control, new()
{ {
var t = new DialogControl()
{
Content = new TView() { DataContext = vm },
DataContext = vm,
};
var host = OverlayDialogManager.GetHost(hostId); var host = OverlayDialogManager.GetHost(hostId);
host?.AddModalDialog(t); if (host is null) return Task.FromResult(DialogResult.None);
return t.ShowAsync<TResult>();
}
public static void Show<TView, TViewModel>(
TViewModel vm,
string? hostId = null,
string? title = null,
DialogMode mode = DialogMode.None,
DialogButton buttons = DialogButton.OKCancel)
where TView: Control, new()
{
var t = new DefaultDialogControl() var t = new DefaultDialogControl()
{ {
Content = new TView() { DataContext = vm }, Content = control,
DataContext = vm, DataContext = vm,
Buttons = buttons,
Title = title,
Mode = mode,
}; };
var host = OverlayDialogManager.GetHost(hostId); ConfigureDefaultDialogControl(t, options);
host?.AddDialog(t); host?.AddModalDialog(t);
return t.ShowAsync<DialogResult>();
} }
public static void ShowCustom<TView, TViewModel>(TViewModel vm, string? hostId = null) public static Task<TResult?> ShowCustomModal<TView, TViewModel, TResult>(TViewModel vm, string? hostId = null,
OverlayDialogOptions? options = null)
where TView: Control, new() where TView: Control, new()
{ {
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return Task.FromResult(default(TResult));
var t = new DialogControl() var t = new DialogControl()
{ {
Content = new TView() { DataContext = vm }, Content = new TView(),
DataContext = vm, DataContext = vm,
}; };
ConfigureDialogControl(t, options);
host?.AddModalDialog(t);
return t.ShowAsync<TResult?>();
}
public static Task<TResult?> ShowCustomModal<TResult>(Control control, object? vm, string? hostId = null,
OverlayDialogOptions? options = null)
{
var host = OverlayDialogManager.GetHost(hostId); var host = OverlayDialogManager.GetHost(hostId);
host?.AddDialog(t); if (host is null) return Task.FromResult(default(TResult));
var view = host.GetDataTemplate(vm)?.Build(vm);
if (view is null) view = new ContentControl();
view.DataContext = vm;
var t = new DialogControl()
{
Content = view,
DataContext = vm,
};
ConfigureDialogControl(t, options);
host?.AddModalDialog(t);
return t.ShowAsync<TResult?>();
}
private static void ConfigureDialogControl(DialogControl control, OverlayDialogOptions? options)
{
if (options is null) options = new OverlayDialogOptions();
control.HorizontalAnchor = options.HorizontalAnchor;
control.VerticalAnchor = options.VerticalAnchor;
control.InitialHorizontalOffset =
control.HorizontalAnchor == HorizontalPosition.Center ? null : options.HorizontalOffset;
control.InitialHorizontalOffset =
options.VerticalAnchor == VerticalPosition.Center ? null : options.VerticalOffset;
control.CanClickOnMaskToClose = options.CanClickOnMaskToClose;
}
private static void ConfigureDefaultDialogControl(DefaultDialogControl control, OverlayDialogOptions? options)
{
if (options is null) options = new OverlayDialogOptions();
control.HorizontalAnchor = options.HorizontalAnchor;
control.VerticalAnchor = options.VerticalAnchor;
control.InitialHorizontalOffset =
control.HorizontalAnchor == HorizontalPosition.Center ? null : options.HorizontalOffset;
control.InitialHorizontalOffset =
options.VerticalAnchor == VerticalPosition.Center ? null : options.VerticalOffset;
control.CanClickOnMaskToClose = options.CanClickOnMaskToClose;
control.Mode = options.Mode;
control.Buttons = options.Buttons;
control.Title = options.Title;
} }

View File

@@ -1,6 +1,7 @@
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.Media; using Avalonia.Media;
@@ -220,4 +221,17 @@ public class OverlayDialogHost : Canvas
Canvas.SetLeft(control, left); Canvas.SetLeft(control, left);
Canvas.SetTop(control, top); Canvas.SetTop(control, top);
} }
internal IDataTemplate? GetDataTemplate(object? o)
{
if (o is null) return null;
IDataTemplate? result = null;
var templates = this.DataTemplates.ToList();
result = templates.FirstOrDefault(a => a.Match(o));
if (result != null) return result;
var resources = this.Resources.Where(a => a.Value is IDataTemplate).Select(a => a.Value)
.OfType<IDataTemplate>();
result = resources.FirstOrDefault(a => a.Match(o));
return result;
}
} }

View File

@@ -0,0 +1,29 @@
using Ursa.Common;
namespace Ursa.Controls;
public enum HorizontalPosition
{
Left,
Center,
Right
}
public enum VerticalPosition
{
Top,
Center,
Bottom
}
public class OverlayDialogOptions
{
public bool CanClickOnMaskToClose { get; set; } = false;
public HorizontalPosition HorizontalAnchor { get; set; } = HorizontalPosition.Center;
public VerticalPosition VerticalAnchor { get; set; } = VerticalPosition.Center;
public double? HorizontalOffset { get; set; } = null;
public double? VerticalOffset { get; set; } = null;
public DialogMode Mode { get; set; } = DialogMode.None;
public DialogButton Buttons { get; set; } = DialogButton.OKCancel;
public string? Title { get; set; } = null;
}