Add ZIndex manage support for DialogLayer

This commit is contained in:
chinboy
2025-11-06 22:37:12 +08:00
parent 97aad9079e
commit 8083ddf1ec
8 changed files with 133 additions and 10 deletions
@@ -21,7 +21,7 @@ public partial class Dialog
public static object? ShowDialog(Control content, object? dataContext = null, DialogOptions? options = null, TopLevel? topLevel = null)
{
var dialogManager = FindDialogManager(topLevel);
var dialog = CreateDialog(content, dataContext, options);
var dialog = CreateDialog(content, dataContext, options);
dialogManager.Children.Add(dialog);
var result = dialog.Open();
dialogManager.Children.Remove(dialog);
@@ -71,6 +71,12 @@ public partial class Dialog
VerticalStartupLocation = options?.VerticalStartupLocation ?? DialogVerticalAnchor.Custom,
Content = content,
DataContext = dataContext,
Width = options?.Width ?? Double.NaN,
Height = options?.Height ?? Double.NaN,
MinWidth = options?.MinWidth ?? 0d,
MinHeight = options?.MinHeight ?? 0d,
MaxWidth = options?.MaxWidth ?? Double.PositiveInfinity,
MaxHeight = options?.MaxHeight ?? Double.PositiveInfinity
};
return dialog;
}
@@ -12,6 +12,13 @@ public record DialogOptions
public bool IsResizable { get; init; } = false;
public bool IsClosable { get; init; } = true;
public bool IsMaximizable { get; init; } = false;
public double MaxHeight { get; init; } = double.PositiveInfinity;
public double MaxWidth { get; init; } = double.PositiveInfinity;
public double MinHeight { get; init; } = 0d;
public double MinWidth { get; init; } = 0d;
public double Width { get; init; } = double.NaN;
public double Height { get; init; } = double.NaN;
/// <summary>
/// 仅仅对 Window Host 类型的弹窗有效
@@ -8,6 +8,7 @@ using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Metadata;
@@ -134,6 +135,7 @@ internal class OverlayDialogHeader : TemplatedControl, IMotionAwareControl
internal event EventHandler? CloseRequest;
internal event EventHandler? MaximizeRequest;
internal event EventHandler? NormalizeRequest;
internal event EventHandler? Pressed;
#endregion
@@ -154,11 +156,6 @@ internal class OverlayDialogHeader : TemplatedControl, IMotionAwareControl
PseudoClasses.Set(StdPseudoClass.Normal, x == OverlayDialogState.Normal);
PseudoClasses.Set(StdPseudoClass.Maximized, x == OverlayDialogState.Maximized);
}),
// window.GetObservable(WindowBase.IsActiveProperty).Subscribe(isActivated =>
// {
// PseudoClasses.Set(StdPseudoClass.Active, isActivated);
// IsActivated = isActivated;
// })
};
}
}
@@ -194,7 +191,13 @@ internal class OverlayDialogHeader : TemplatedControl, IMotionAwareControl
}
}
}
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnPointerPressed(e);
Pressed?.Invoke(this, EventArgs.Empty);
}
private void HandleCloseButtonClicked(object? sender, RoutedEventArgs e)
{
CloseRequest?.Invoke(this, EventArgs.Empty);
@@ -176,6 +176,8 @@ internal class OverlayDialogHost : ContentControl,
#endregion
internal event EventHandler? HeaderPressed;
#region 内部属性定义
internal static readonly DirectProperty<OverlayDialogHost, bool> IsDraggingProperty =
@@ -577,6 +579,10 @@ internal class OverlayDialogHost : ContentControl,
if (_header != null)
{
_header.SetCurrentValue(OverlayDialogHeader.IsDialogMaximizedProperty, WindowState == OverlayDialogState.Maximized);
_header.Pressed += (sender, args) =>
{
HeaderPressed?.Invoke(this, EventArgs.Empty);
};
}
if (_buttonBox != null)
{
@@ -895,4 +901,10 @@ internal class OverlayDialogHost : ContentControl,
Transitions = null;
}
}
internal void NotifyChangeZIndex(int zindex)
{
_dialogMask.SetCurrentValue(OverlayDialogMask.ZIndexProperty, zindex - 1);
SetCurrentValue(ZIndexProperty, zindex);
}
}
@@ -66,6 +66,7 @@
<Setter Property="Margin" Value="{DynamicResource {x:Static atom:DialogTokenKey.HeaderMarginBottom}}" />
</Style>
<Style Selector="^ /template/ Border#ShadowFrame">
<Setter Property="Background" Value="{DynamicResource {x:Static atom:DialogTokenKey.ContentBg}}" />
</Style>
+54 -1
View File
@@ -1,10 +1,11 @@
using System.Collections.Specialized;
using Avalonia;
using Avalonia.Controls;
using Avalonia.VisualTree;
namespace AtomUI.Controls.Primitives;
public class DialogLayer : Canvas
internal class DialogLayer : Canvas
{
protected override bool BypassFlowDirectionPolicies => true;
@@ -14,6 +15,58 @@ public class DialogLayer : Canvas
{
ClipToBoundsProperty.OverrideDefaultValue<DialogLayer>(true);
}
public DialogLayer()
{
Children.CollectionChanged += HandleDialogChanged;
}
private void HandleDialogChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
if (e.NewItems != null)
{
foreach (Control child in e.NewItems)
{
if (child is OverlayDialogHost overlayDialogHost)
{
overlayDialogHost.HeaderPressed += HandleOverlayDialogClicked;
}
}
}
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
if (e.OldItems != null)
{
foreach (Control child in e.OldItems)
{
if (child is OverlayDialogHost overlayDialogHost)
{
overlayDialogHost.HeaderPressed -= HandleOverlayDialogClicked;
}
}
}
}
}
private void HandleOverlayDialogClicked(object? sender, EventArgs e)
{
var maxZIndex = 0;
foreach (Control child in Children)
{
if (child is OverlayDialogHost overlayDialogHost)
{
maxZIndex = Math.Max(maxZIndex, overlayDialogHost.ZIndex);
}
}
if (sender is OverlayDialogHost clickedOverlayDialogHost)
{
clickedOverlayDialogHost.NotifyChangeZIndex(maxZIndex + 2);
}
}
public static DialogLayer? GetDialogLayer(Visual visual)
{
@@ -19,7 +19,7 @@ public class VisualLayerManager : AvaloniaVisualLayerManager
return null;
}
public DialogLayer DialogLayer
internal DialogLayer DialogLayer
{
get
{
+42 -1
View File
@@ -1,5 +1,8 @@
using AtomUI.Controls.Themes;
using AtomUI.Controls.DesignTokens;
using AtomUI.Controls.Themes;
using AtomUI.IconPkg;
using AtomUI.Theme;
using AtomUI.Theme.Styling;
using AtomUI.Theme.Utils;
using AtomUI.Utils;
using Avalonia;
@@ -128,6 +131,7 @@ public class SpinIndicator : TemplatedControl,
public SpinIndicator()
{
this.RegisterResources();
ConfigureInstanceStyles();
}
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
@@ -255,4 +259,41 @@ public class SpinIndicator : TemplatedControl,
context.DrawEllipse(DotBgBrush, null, itemRect);
}
}
private void ConfigureInstanceStyles()
{
{
var middleStyle = new Style(x =>
x.PropertyEquals(SizeTypeProperty, SizeType.Middle));
var iconStyle = new Style(x =>
x.Nesting().Descendant().OfType<ContentPresenter>().Name(SpinThemeConstants.CustomIndicatorPresenterPart).Child()
.OfType<Icon>());
iconStyle.Add(Icon.WidthProperty, SpinTokenKey.IndicatorSize);
iconStyle.Add(Icon.HeightProperty, SpinTokenKey.IndicatorSize);
middleStyle.Add(iconStyle);
Styles.Add(middleStyle);
}
{
var smallStyle = new Style(x =>
x.PropertyEquals(SizeTypeProperty, SizeType.Small));
var iconStyle = new Style(x =>
x.Nesting().Descendant().OfType<ContentPresenter>().Name(SpinThemeConstants.CustomIndicatorPresenterPart).Child()
.OfType<Icon>());
iconStyle.Add(Icon.WidthProperty, SpinTokenKey.IndicatorSizeSM);
iconStyle.Add(Icon.HeightProperty, SpinTokenKey.IndicatorSizeSM);
smallStyle.Add(iconStyle);
Styles.Add(smallStyle);
}
{
var largeStyle = new Style(x =>
x.PropertyEquals(SizeTypeProperty, SizeType.Large));
var iconStyle = new Style(x =>
x.Nesting().Descendant().OfType<ContentPresenter>().Name(SpinThemeConstants.CustomIndicatorPresenterPart).Child()
.OfType<Icon>());
iconStyle.Add(Icon.WidthProperty, SpinTokenKey.IndicatorSizeLG);
iconStyle.Add(Icon.HeightProperty, SpinTokenKey.IndicatorSizeLG);
largeStyle.Add(iconStyle);
Styles.Add(largeStyle);
}
}
}