diff --git a/demo/Ursa.Demo/Dialogs/DialogWithActionViewModel.cs b/demo/Ursa.Demo/Dialogs/DialogWithActionViewModel.cs index 5f5aa45..016fbbd 100644 --- a/demo/Ursa.Demo/Dialogs/DialogWithActionViewModel.cs +++ b/demo/Ursa.Demo/Dialogs/DialogWithActionViewModel.cs @@ -45,6 +45,6 @@ public partial class DialogWithActionViewModel: ObservableObject, IDialogContext private async Task ShowDialog() { - await OverlayDialog.ShowCustomModalAsync(new DialogWithActionViewModel()); + await OverlayDialog.ShowCustomModal(new DialogWithActionViewModel()); } } \ No newline at end of file diff --git a/demo/Ursa.Demo/ViewModels/DialogDemoViewModel.cs b/demo/Ursa.Demo/ViewModels/DialogDemoViewModel.cs index 901f183..2b7ec92 100644 --- a/demo/Ursa.Demo/ViewModels/DialogDemoViewModel.cs +++ b/demo/Ursa.Demo/ViewModels/DialogDemoViewModel.cs @@ -103,12 +103,15 @@ public class DialogDemoViewModel: ObservableObject { if (IsModal) { - DefaultResult = await OverlayDialog.ShowModalAsync( + DefaultResult = await OverlayDialog.ShowModal( 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( 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( + Result = await OverlayDialog.ShowCustomModal( vm, IsGlobal ? null : "LocalHost"); Date = vm.Date; } diff --git a/src/Ursa/Controls/Dialog/Dialog.cs b/src/Ursa/Controls/Dialog/Dialog.cs index ec987ad..c7dc4a6 100644 --- a/src/Ursa/Controls/Dialog/Dialog.cs +++ b/src/Ursa/Controls/Dialog/Dialog.cs @@ -38,6 +38,13 @@ public static class Dialog } } + /// + /// Show a Window Dialog that with all content fully customized. And the owner of the dialog is specified. + /// + /// View to show in Dialog Window + /// ViewModel + /// Owner Window + /// Dialog options to configure the window. 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 } } + /// + /// Show a Modal Dialog Window with default style. + /// + /// + /// + /// + /// + /// + /// public static Task ShowModal(TViewModel vm, Window? owner = null, DialogOptions? options = null) where TView: Control, new() @@ -76,6 +92,14 @@ public static class Dialog return window.ShowDialog(owner); } + /// + /// Show a Modal Dialog Window with default style. + /// + /// + /// + /// + /// + /// public static Task 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(owner); } + /// + /// Show a Modal Dialog Window with all content fully customized. + /// + /// + /// + /// + /// + /// + /// + /// public static Task ShowCustomModal(TViewModel vm, Window? owner = null, DialogOptions? options = null) where TView: Control, new() @@ -112,6 +146,15 @@ public static class Dialog return window.ShowDialog(owner); } + /// + /// Show a Modal Dialog Window with all content fully customized. + /// + /// + /// + /// + /// + /// + /// public static Task ShowCustomModal(Control view, object? vm, Window? owner = null, DialogOptions? options = null) { @@ -130,12 +173,21 @@ public static class Dialog return window.ShowDialog(owner); } + /// + /// Get the main window of the application as default owner of the dialog. + /// + /// private static Window? GetMainWindow() { var lifetime = Application.Current?.ApplicationLifetime; return lifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } w } ? w : null; } + /// + /// Attach options to dialog window. + /// + /// + /// private static void AssignOptionsToDialogWindow(DialogWindow window, DialogOptions? options) { if (options is null) @@ -157,6 +209,11 @@ public static class Dialog } } + /// + /// Attach options to default dialog window. + /// + /// + /// private static void AssignOptionsToDefaultDialogWindow(DefaultDialogWindow window, DialogOptions? options) { if (options is null) @@ -179,6 +236,4 @@ public static class Dialog } } } - - } \ No newline at end of file diff --git a/src/Ursa/Controls/Dialog/DialogControl.cs b/src/Ursa/Controls/Dialog/DialogControl.cs index 1d3c1f5..4186580 100644 --- a/src/Ursa/Controls/Dialog/DialogControl.cs +++ b/src/Ursa/Controls/Dialog/DialogControl.cs @@ -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? LayerChanged; public event EventHandler? DialogControlClosing; static DialogControl() - { + { DataContextProperty.Changed.AddClassHandler((o, e) => o.OnDataContextChange(e)); } diff --git a/src/Ursa/Controls/Dialog/DialogOptions.cs b/src/Ursa/Controls/Dialog/DialogOptions.cs index 4d50db7..7196597 100644 --- a/src/Ursa/Controls/Dialog/DialogOptions.cs +++ b/src/Ursa/Controls/Dialog/DialogOptions.cs @@ -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; } \ No newline at end of file diff --git a/src/Ursa/Controls/Dialog/OverlayDialog.cs b/src/Ursa/Controls/Dialog/OverlayDialog.cs index 3e74325..323a169 100644 --- a/src/Ursa/Controls/Dialog/OverlayDialog.cs +++ b/src/Ursa/Controls/Dialog/OverlayDialog.cs @@ -5,72 +5,188 @@ namespace Ursa.Controls; public static class OverlayDialog { - public static Task ShowModalAsync( - TViewModel vm, - string? hostId = null, - string? title = null, - DialogMode mode = DialogMode.None, - DialogButton buttons = DialogButton.OKCancel) + public static void Show(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(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 ShowModal(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(); } - - public static Task ShowCustomModalAsync( - TViewModel vm, - string? hostId = null) - where TView: Control, new() + + public static Task 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(); - } - - public static void Show( - 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(); } - - public static void ShowCustom(TViewModel vm, string? hostId = null) + + public static Task ShowCustomModal(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(); + } + + public static Task ShowCustomModal(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(); + } + + 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; } diff --git a/src/Ursa/Controls/Dialog/OverlayDialogHost.cs b/src/Ursa/Controls/Dialog/OverlayDialogHost.cs index 246c19b..522f14e 100644 --- a/src/Ursa/Controls/Dialog/OverlayDialogHost.cs +++ b/src/Ursa/Controls/Dialog/OverlayDialogHost.cs @@ -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(); + result = resources.FirstOrDefault(a => a.Match(o)); + return result; + } } \ No newline at end of file diff --git a/src/Ursa/Controls/Dialog/OverlayDialogOptions.cs b/src/Ursa/Controls/Dialog/OverlayDialogOptions.cs new file mode 100644 index 0000000..eb94c71 --- /dev/null +++ b/src/Ursa/Controls/Dialog/OverlayDialogOptions.cs @@ -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; +} \ No newline at end of file