feat: implement multi layer dialog.
This commit is contained in:
@@ -8,7 +8,7 @@ namespace Ursa.Controls;
|
||||
|
||||
public static class DialogBox
|
||||
{
|
||||
public static async Task<TResult?> ShowAsync<TView, TViewModel, TResult>(TViewModel vm)
|
||||
public static async Task<TResult?> ShowModalAsync<TView, TViewModel, TResult>(TViewModel vm)
|
||||
where TView : Control, new()
|
||||
{
|
||||
var window = new DialogWindow()
|
||||
@@ -37,28 +37,68 @@ public static class DialogBox
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<TResult> ShowAsync<TView, TViewModel, TResult>(Window owner, TViewModel vm) where
|
||||
public static async Task<TResult> ShowModalAsync<TView, TViewModel, TResult>(Window owner, TViewModel vm) where
|
||||
TView: Control, new()
|
||||
{
|
||||
var window = new DialogWindow();
|
||||
window.Content = new TView();
|
||||
window.DataContext = vm;
|
||||
var window = new DialogWindow
|
||||
{
|
||||
Content = new TView() { DataContext = vm },
|
||||
DataContext = vm
|
||||
};
|
||||
return await window.ShowDialog<TResult>(owner);
|
||||
}
|
||||
|
||||
|
||||
public static Task<TResult> ShowOverlayAsync<TView, TViewModel, TResult>(TViewModel vm, string hostId)
|
||||
public static Task<TResult> ShowOverlayModalAsync<TView, TViewModel, TResult>(TViewModel vm, string hostId)
|
||||
where TView : Control, new()
|
||||
where TViewModel: new()
|
||||
{
|
||||
var t = new DialogControl()
|
||||
{
|
||||
Content = new TView(){ DataContext = vm },
|
||||
DataContext = vm,
|
||||
};
|
||||
t.DataContext = vm;
|
||||
var host = OverlayDialogManager.GetOverlayDialogHost(hostId);
|
||||
host?.AddDialog(t);
|
||||
host?.AddModalDialog(t);
|
||||
return t.ShowAsync<TResult>();
|
||||
}
|
||||
|
||||
public static Task<TResult> ShowOverlayModalAsync<TView, TViewModel, TResult>(TViewModel vm, string hostId,
|
||||
DialogOptions options)
|
||||
where TView : Control, new()
|
||||
{
|
||||
var t = new DialogControl()
|
||||
{
|
||||
Content = new TView() { DataContext = vm },
|
||||
DataContext = vm,
|
||||
ExtendToClientArea = options.ExtendToClientArea,
|
||||
Title = options.Title,
|
||||
};
|
||||
var host = OverlayDialogManager.GetOverlayDialogHost(hostId);
|
||||
host?.AddModalDialog(t);
|
||||
return t.ShowAsync<TResult>();
|
||||
}
|
||||
|
||||
public static void ShowOverlay<TView, TViewModel>(TViewModel vm, string hostId)
|
||||
where TView: Control, new()
|
||||
{
|
||||
var t = new DialogControl()
|
||||
{
|
||||
Content = new TView() { DataContext = vm },
|
||||
DataContext = vm,
|
||||
};
|
||||
var host = OverlayDialogManager.GetOverlayDialogHost(hostId);
|
||||
host?.AddDialog(t);
|
||||
}
|
||||
|
||||
public static void ShowOverlay<TView, TViewModel>(TViewModel vm, string hostId, DialogOptions options)
|
||||
where TView: Control, new()
|
||||
{
|
||||
var t = new DialogControl()
|
||||
{
|
||||
Content = new TView() { DataContext = vm },
|
||||
DataContext = vm,
|
||||
};
|
||||
var host = OverlayDialogManager.GetOverlayDialogHost(hostId);
|
||||
host?.AddModalDialog(t);
|
||||
}
|
||||
}
|
||||
@@ -9,18 +9,39 @@ namespace Ursa.Controls;
|
||||
|
||||
[TemplatePart(PART_CloseButton, typeof(Button))]
|
||||
[TemplatePart(PART_TitleArea, typeof(Panel))]
|
||||
[PseudoClasses(PC_ExtendClientArea)]
|
||||
public class DialogControl: ContentControl
|
||||
{
|
||||
public const string PART_CloseButton = "PART_CloseButton";
|
||||
public const string PART_TitleArea = "PART_TitleArea";
|
||||
public const string PC_ExtendClientArea = ":extend";
|
||||
|
||||
private Button? _closeButton;
|
||||
private Panel? _titleArea;
|
||||
public event EventHandler<object?>? OnClose;
|
||||
|
||||
public static readonly StyledProperty<string?> TitleProperty = AvaloniaProperty.Register<DialogControl, string?>(
|
||||
nameof(Title));
|
||||
|
||||
public string? Title
|
||||
{
|
||||
get => GetValue(TitleProperty);
|
||||
set => SetValue(TitleProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<bool> ExtendToClientAreaProperty = AvaloniaProperty.Register<DialogControl, bool>(
|
||||
nameof(ExtendToClientArea));
|
||||
|
||||
public bool ExtendToClientArea
|
||||
{
|
||||
get => GetValue(ExtendToClientAreaProperty);
|
||||
set => SetValue(ExtendToClientAreaProperty, value);
|
||||
}
|
||||
|
||||
static DialogControl()
|
||||
{
|
||||
DataContextProperty.Changed.AddClassHandler<DialogControl, object?>((o, e) => o.OnDataContextChange(e));
|
||||
ExtendToClientAreaProperty.Changed.AddClassHandler<DialogControl, bool>((o, e) => o.PseudoClasses.Set(PC_ExtendClientArea, e.NewValue.Value));
|
||||
}
|
||||
|
||||
private void OnDataContextChange(AvaloniaPropertyChangedEventArgs<object?> args)
|
||||
@@ -34,7 +55,6 @@ public class DialogControl: ContentControl
|
||||
{
|
||||
newContext.Closed += Close;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
using Ursa.Common;
|
||||
|
||||
namespace Ursa.Controls;
|
||||
|
||||
public record DialogOptions
|
||||
{
|
||||
public bool ShowCloseButton { get; set; } = true;
|
||||
public string? Title { get; set; }
|
||||
public bool ExtendToClientArea { get; set; } = false;
|
||||
public DialogButton DefaultButtons { get; set; } = DialogButton.OKCancel;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Metadata;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Input;
|
||||
@@ -15,21 +16,21 @@ public class DialogWindow: Window
|
||||
|
||||
private Button? _closeButton;
|
||||
|
||||
protected override void OnDataContextBeginUpdate()
|
||||
static DialogWindow()
|
||||
{
|
||||
base.OnDataContextBeginUpdate();
|
||||
if (DataContext is IDialogContext context)
|
||||
{
|
||||
context.Closed-= OnDialogClose;
|
||||
}
|
||||
DataContextProperty.Changed.AddClassHandler<DialogWindow, object?>((o, e) => o.OnDataContextChange(e));
|
||||
}
|
||||
|
||||
protected override void OnDataContextEndUpdate()
|
||||
|
||||
private void OnDataContextChange(AvaloniaPropertyChangedEventArgs<object?> args)
|
||||
{
|
||||
base.OnDataContextEndUpdate();
|
||||
if (DataContext is IDialogContext context)
|
||||
if (args.OldValue.Value is IDialogContext oldContext)
|
||||
{
|
||||
context.Closed += OnDialogClose;
|
||||
oldContext.Closed-= OnDialogClose;
|
||||
}
|
||||
|
||||
if (args.NewValue.Value is IDialogContext newContext)
|
||||
{
|
||||
newContext.Closed += OnDialogClose;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,39 +15,44 @@ public class OverlayDialogHost: Canvas
|
||||
{
|
||||
private readonly List<DialogControl> _dialogs = new();
|
||||
private readonly List<DialogControl> _modalDialogs = new();
|
||||
private readonly List<Border> _masks = new();
|
||||
|
||||
public static readonly StyledProperty<string> HostIdProperty = AvaloniaProperty.Register<OverlayDialogHost, string>(
|
||||
nameof(HostId));
|
||||
|
||||
public string HostId
|
||||
{
|
||||
get => GetValue(HostIdProperty);
|
||||
set => SetValue(HostIdProperty, value);
|
||||
}
|
||||
public string? HostId { get; set; }
|
||||
|
||||
private Point _lastPoint;
|
||||
|
||||
public static readonly StyledProperty<IBrush?> OverlayMaskBrushProperty = AvaloniaProperty.Register<OverlayDialogHost, IBrush?>(
|
||||
nameof(OverlayMaskBrush));
|
||||
|
||||
public IBrush? OverlayMaskBrush
|
||||
{
|
||||
get => GetValue(OverlayMaskBrushProperty);
|
||||
set => SetValue(OverlayMaskBrushProperty, value);
|
||||
}
|
||||
|
||||
private Border CreateOverlayMask() => new()
|
||||
{
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
VerticalAlignment = VerticalAlignment.Stretch,
|
||||
Width = this.Bounds.Width,
|
||||
Height = this.Bounds.Height,
|
||||
[!BackgroundProperty] = this[!OverlayMaskBrushProperty],
|
||||
IsVisible = true,
|
||||
};
|
||||
|
||||
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||
{
|
||||
base.OnAttachedToVisualTree(e);
|
||||
OverlayDialogManager.RegisterOverlayDialogHost(this, HostId);
|
||||
this.Children.Add(new Border()
|
||||
{
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
VerticalAlignment = VerticalAlignment.Stretch,
|
||||
Background = Brushes.Black,
|
||||
Opacity = 0.3,
|
||||
IsVisible = false,
|
||||
});
|
||||
}
|
||||
|
||||
protected override void OnSizeChanged(SizeChangedEventArgs e)
|
||||
{
|
||||
base.OnSizeChanged(e);
|
||||
if (this.Children.Count > 0)
|
||||
for (int i = 0; i < _masks.Count; i++)
|
||||
{
|
||||
this.Children[0].Width = this.Bounds.Width;
|
||||
this.Children[0].Height = this.Bounds.Height;
|
||||
_masks[i].Width = this.Bounds.Width;
|
||||
_masks[i].Width = this.Bounds.Height;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,11 +92,8 @@ public class OverlayDialogHost: Canvas
|
||||
public void AddDialog(DialogControl control)
|
||||
{
|
||||
this.Children.Add(control);
|
||||
_dialogs.Add(control);
|
||||
control.OnClose += OnDialogClose;
|
||||
if (this.Children.Count > 1)
|
||||
{
|
||||
this.Children[0].IsVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDialogClose(object sender, object? e)
|
||||
@@ -100,16 +102,38 @@ public class OverlayDialogHost: Canvas
|
||||
{
|
||||
this.Children.Remove(control);
|
||||
control.OnClose -= OnDialogClose;
|
||||
if (this.Children.Count == 1)
|
||||
if (_dialogs.Contains(control))
|
||||
{
|
||||
this.Children[0].IsVisible = false;
|
||||
_dialogs.Remove(control);
|
||||
}
|
||||
else if(_modalDialogs.Contains(control))
|
||||
{
|
||||
_modalDialogs.Remove(control);
|
||||
if (_masks.Count > 0)
|
||||
{
|
||||
var last = _masks.Last();
|
||||
this.Children.Remove(last);
|
||||
_masks.Remove(last);
|
||||
if (_masks.Count > 0)
|
||||
{
|
||||
_masks.Last().IsVisible= true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void AddModalDialog(DialogControl control)
|
||||
{
|
||||
var mask = CreateOverlayMask();
|
||||
this.Children.Add(mask);
|
||||
this.Children.Add(control);
|
||||
_modalDialogs.Add(control);
|
||||
for (int i = 0; i < _masks.Count; i++)
|
||||
{
|
||||
_masks[i].IsVisible = false;
|
||||
}
|
||||
_masks.Add(mask);
|
||||
control.OnClose += OnDialogClose;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user