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()
{
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)
{
DefaultResult = await OverlayDialog.ShowModalAsync<PlainDialog, PlainDialogViewModel>(
DefaultResult = await OverlayDialog.ShowModal<PlainDialog, PlainDialogViewModel>(
vm,
IsGlobal ? null : "LocalHost",
"Please select a date",
SelectedMode,
SelectedButton
new OverlayDialogOptions()
{
Title = "Please select a date",
Mode = SelectedMode,
Buttons = SelectedButton
}
);
Date = vm.Date;
}
@@ -117,9 +120,12 @@ public class DialogDemoViewModel: ObservableObject
OverlayDialog.Show<PlainDialog, PlainDialogViewModel>(
new PlainDialogViewModel(),
IsGlobal ? null : "LocalHost",
"Please select a date",
SelectedMode,
SelectedButton);
new OverlayDialogOptions()
{
Title = "Please select a date",
Mode = SelectedMode,
Buttons = SelectedButton
});
}
}
@@ -148,7 +154,7 @@ public class DialogDemoViewModel: ObservableObject
{
if (IsModal)
{
Result = await OverlayDialog.ShowCustomModalAsync<DialogWithAction, DialogWithActionViewModel, bool>(
Result = await OverlayDialog.ShowCustomModal<DialogWithAction, DialogWithActionViewModel, bool>(
vm, IsGlobal ? null : "LocalHost");
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)
{
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,
DialogOptions? options = null)
where TView: Control, new()
@@ -76,6 +92,14 @@ public static class Dialog
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)
{
var window = new DefaultDialogWindow
@@ -93,6 +117,16 @@ public static class Dialog
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,
DialogOptions? options = null)
where TView: Control, new()
@@ -112,6 +146,15 @@ public static class Dialog
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,
DialogOptions? options = null)
{
@@ -130,12 +173,21 @@ public static class Dialog
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()
{
var lifetime = Application.Current?.ApplicationLifetime;
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)
{
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)
{
if (options is null)
@@ -179,6 +236,4 @@ public static class Dialog
}
}
}
}

View File

@@ -19,11 +19,18 @@ public class DialogControl: ContentControl
protected internal Button? _closeButton;
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<object?>? DialogControlClosing;
static DialogControl()
{
{
DataContextProperty.Changed.AddClassHandler<DialogControl, object?>((o, e) => o.OnDataContextChange(e));
}

View File

@@ -24,9 +24,4 @@ public class DialogOptions
public DialogMode Mode { get; set; } = DialogMode.None;
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 Task<DialogResult> ShowModalAsync<TView, TViewModel>(
TViewModel vm,
string? hostId = null,
string? title = null,
DialogMode mode = DialogMode.None,
DialogButton buttons = DialogButton.OKCancel)
public static void Show<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 DefaultDialogControl()
{
Content = new TView(){ 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);
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);
return t.ShowAsync<DialogResult>();
}
public static Task<TResult> ShowCustomModalAsync<TView, TViewModel, TResult>(
TViewModel vm,
string? hostId = null)
where TView: Control, new()
public static Task<DialogResult> ShowModal(Control control, object? vm, string? hostId = null,
OverlayDialogOptions? options = null)
{
var t = new DialogControl()
{
Content = new TView() { DataContext = vm },
DataContext = vm,
};
var host = OverlayDialogManager.GetHost(hostId);
host?.AddModalDialog(t);
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()
{
if (host is null) return Task.FromResult(DialogResult.None);
var t = new DefaultDialogControl()
{
Content = new TView() { DataContext = vm },
Content = control,
DataContext = vm,
Buttons = buttons,
Title = title,
Mode = mode,
};
var host = OverlayDialogManager.GetHost(hostId);
host?.AddDialog(t);
ConfigureDefaultDialogControl(t, options);
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()
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return Task.FromResult(default(TResult));
var t = new DialogControl()
{
Content = new TView() { DataContext = vm },
Content = new TView(),
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);
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.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Media;
@@ -220,4 +221,17 @@ public class OverlayDialogHost : Canvas
Canvas.SetLeft(control, left);
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;
}