Merge pull request #647 from irihitech/ursa_host

Make UrsaWindow/UrsaView's built in OverlayDialogHost part of logical tree.
This commit is contained in:
Zhang Dian
2025-04-11 14:10:15 +08:00
committed by GitHub
4 changed files with 201 additions and 57 deletions

View File

@@ -1,55 +1,103 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
namespace Ursa.Controls;
/// <summary>
/// Ursa window is designed to
/// Represents a custom content control with additional properties for managing a title bar and related content.
/// This control can be used as the top level container for platforms without windowing toplevel support.
/// </summary>
public class UrsaView: ContentControl
public class UrsaView : ContentControl
{
/// <summary>
/// The name of the dialog host part in the control template.
/// </summary>
public const string PART_DialogHost = "PART_DialogHost";
/// <summary>
/// Defines the visibility of the title bar.
/// </summary>
public static readonly StyledProperty<bool> IsTitleBarVisibleProperty =
UrsaWindow.IsTitleBarVisibleProperty.AddOwner<UrsaView>();
/// <summary>
/// Defines the content on the left side of the control.
/// </summary>
public static readonly StyledProperty<object?> LeftContentProperty =
UrsaWindow.LeftContentProperty.AddOwner<UrsaView>();
/// <summary>
/// Defines the content on the right side of the control.
/// </summary>
public static readonly StyledProperty<object?> RightContentProperty =
UrsaWindow.RightContentProperty.AddOwner<UrsaView>();
/// <summary>
/// Defines the content of the title bar.
/// </summary>
public static readonly StyledProperty<object?> TitleBarContentProperty =
UrsaWindow.TitleBarContentProperty.AddOwner<UrsaView>();
/// <summary>
/// Defines the margin of the title bar.
/// </summary>
public static readonly StyledProperty<Thickness> TitleBarMarginProperty =
UrsaWindow.TitleBarMarginProperty.AddOwner<UrsaView>();
/// <summary>
/// Gets or sets a value indicating whether the title bar is visible.
/// </summary>
public bool IsTitleBarVisible
{
get => GetValue(IsTitleBarVisibleProperty);
set => SetValue(IsTitleBarVisibleProperty, value);
}
public static readonly StyledProperty<object?> LeftContentProperty =
UrsaWindow.LeftContentProperty.AddOwner<UrsaView>();
/// <summary>
/// Gets or sets the content on the left side of the control.
/// </summary>
public object? LeftContent
{
get => GetValue(LeftContentProperty);
set => SetValue(LeftContentProperty, value);
}
public static readonly StyledProperty<object?> RightContentProperty =
UrsaWindow.RightContentProperty.AddOwner<UrsaView>();
/// <summary>
/// Gets or sets the content on the right side of the control.
/// </summary>
public object? RightContent
{
get => GetValue(RightContentProperty);
set => SetValue(RightContentProperty, value);
}
public static readonly StyledProperty<object?> TitleBarContentProperty =
UrsaWindow.TitleBarContentProperty.AddOwner<UrsaView>();
/// <summary>
/// Gets or sets the content of the title bar.
/// </summary>
public object? TitleBarContent
{
get => GetValue(TitleBarContentProperty);
set => SetValue(TitleBarContentProperty, value);
}
public static readonly StyledProperty<Thickness> TitleBarMarginProperty =
UrsaWindow.TitleBarMarginProperty.AddOwner<UrsaView>();
/// <summary>
/// Gets or sets the margin of the title bar.
/// </summary>
public Thickness TitleBarMargin
{
get => GetValue(TitleBarMarginProperty);
set => SetValue(TitleBarMarginProperty, value);
}
/// <summary>
/// Applies the control template and initializes the dialog host if present.
/// </summary>
/// <param name="e">The event arguments containing the template information.</param>
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
var host = e.NameScope.Find<OverlayDialogHost>(PART_DialogHost);
if (host is not null) LogicalChildren.Add(host);
}
}

View File

@@ -1,112 +1,205 @@
using System.ComponentModel;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
namespace Ursa.Controls;
/// <summary>
/// Ursa Window is an advanced Window control that provides a lot of features and customization options.
/// Ursa Window is an advanced Window control that provides a lot of features and customization options.
/// </summary>
public class UrsaWindow: Window
public class UrsaWindow : Window
{
/// <summary>
/// The name of the dialog host part in the control template.
/// </summary>
public const string PART_DialogHost = "PART_DialogHost";
/// <summary>
/// Defines the visibility of the full-screen button.
/// </summary>
public static readonly StyledProperty<bool> IsFullScreenButtonVisibleProperty =
AvaloniaProperty.Register<UrsaWindow, bool>(
nameof(IsFullScreenButtonVisible));
/// <summary>
/// Defines the visibility of the minimize button.
/// </summary>
public static readonly StyledProperty<bool> IsMinimizeButtonVisibleProperty =
AvaloniaProperty.Register<UrsaWindow, bool>(
nameof(IsMinimizeButtonVisible), true);
/// <summary>
/// Defines the visibility of the restore button.
/// </summary>
public static readonly StyledProperty<bool> IsRestoreButtonVisibleProperty =
AvaloniaProperty.Register<UrsaWindow, bool>(
nameof(IsRestoreButtonVisible), true);
/// <summary>
/// Defines the visibility of the close button.
/// </summary>
public static readonly StyledProperty<bool> IsCloseButtonVisibleProperty =
AvaloniaProperty.Register<UrsaWindow, bool>(
nameof(IsCloseButtonVisible), true);
/// <summary>
/// Defines the visibility of the title bar.
/// </summary>
public static readonly StyledProperty<bool> IsTitleBarVisibleProperty = AvaloniaProperty.Register<UrsaWindow, bool>(
nameof(IsTitleBarVisible), true);
/// <summary>
/// Defines the visibility of the managed resizer.
/// </summary>
public static readonly StyledProperty<bool> IsManagedResizerVisibleProperty =
AvaloniaProperty.Register<UrsaWindow, bool>(
nameof(IsManagedResizerVisible));
/// <summary>
/// Defines the content of the title bar.
/// </summary>
public static readonly StyledProperty<object?> TitleBarContentProperty =
AvaloniaProperty.Register<UrsaWindow, object?>(
nameof(TitleBarContent));
/// <summary>
/// Defines the content on the left side of the window.
/// </summary>
public static readonly StyledProperty<object?> LeftContentProperty = AvaloniaProperty.Register<UrsaWindow, object?>(
nameof(LeftContent));
/// <summary>
/// Defines the content on the right side of the window.
/// </summary>
public static readonly StyledProperty<object?> RightContentProperty =
AvaloniaProperty.Register<UrsaWindow, object?>(
nameof(RightContent));
/// <summary>
/// Defines the margin of the title bar.
/// </summary>
public static readonly StyledProperty<Thickness> TitleBarMarginProperty =
AvaloniaProperty.Register<UrsaWindow, Thickness>(
nameof(TitleBarMargin));
private bool _canClose;
/// <summary>
/// Gets the style key override for the control.
/// </summary>
protected override Type StyleKeyOverride => typeof(UrsaWindow);
public static readonly StyledProperty<bool> IsFullScreenButtonVisibleProperty = AvaloniaProperty.Register<UrsaWindow, bool>(
nameof(IsFullScreenButtonVisible));
/// <summary>
/// Gets or sets a value indicating whether the full-screen button is visible.
/// </summary>
public bool IsFullScreenButtonVisible
{
get => GetValue(IsFullScreenButtonVisibleProperty);
set => SetValue(IsFullScreenButtonVisibleProperty, value);
}
public static readonly StyledProperty<bool> IsMinimizeButtonVisibleProperty = AvaloniaProperty.Register<UrsaWindow, bool>(
nameof(IsMinimizeButtonVisible), true);
/// <summary>
/// Gets or sets a value indicating whether the minimize button is visible.
/// </summary>
public bool IsMinimizeButtonVisible
{
get => GetValue(IsMinimizeButtonVisibleProperty);
set => SetValue(IsMinimizeButtonVisibleProperty, value);
}
public static readonly StyledProperty<bool> IsRestoreButtonVisibleProperty = AvaloniaProperty.Register<UrsaWindow, bool>(
nameof(IsRestoreButtonVisible), true);
/// <summary>
/// Gets or sets a value indicating whether the restore button is visible.
/// </summary>
public bool IsRestoreButtonVisible
{
get => GetValue(IsRestoreButtonVisibleProperty);
set => SetValue(IsRestoreButtonVisibleProperty, value);
}
public static readonly StyledProperty<bool> IsCloseButtonVisibleProperty = AvaloniaProperty.Register<UrsaWindow, bool>(
nameof(IsCloseButtonVisible), true);
/// <summary>
/// Gets or sets a value indicating whether the close button is visible.
/// </summary>
public bool IsCloseButtonVisible
{
get => GetValue(IsCloseButtonVisibleProperty);
set => SetValue(IsCloseButtonVisibleProperty, value);
}
public static readonly StyledProperty<bool> IsTitleBarVisibleProperty = AvaloniaProperty.Register<UrsaWindow, bool>(
nameof(IsTitleBarVisible), true);
/// <summary>
/// Gets or sets a value indicating whether the title bar is visible.
/// </summary>
public bool IsTitleBarVisible
{
get => GetValue(IsTitleBarVisibleProperty);
set => SetValue(IsTitleBarVisibleProperty, value);
}
public static readonly StyledProperty<bool> IsManagedResizerVisibleProperty = AvaloniaProperty.Register<UrsaWindow, bool>(
nameof(IsManagedResizerVisible));
/// <summary>
/// Gets or sets a value indicating whether the managed resizer is visible.
/// </summary>
public bool IsManagedResizerVisible
{
get => GetValue(IsManagedResizerVisibleProperty);
set => SetValue(IsManagedResizerVisibleProperty, value);
}
public static readonly StyledProperty<object?> TitleBarContentProperty = AvaloniaProperty.Register<UrsaWindow, object?>(
nameof(TitleBarContent));
/// <summary>
/// Gets or sets the content of the title bar.
/// </summary>
public object? TitleBarContent
{
get => GetValue(TitleBarContentProperty);
set => SetValue(TitleBarContentProperty, value);
}
public static readonly StyledProperty<object?> LeftContentProperty = AvaloniaProperty.Register<UrsaWindow, object?>(
nameof(LeftContent));
/// <summary>
/// Gets or sets the content on the left side of the window.
/// </summary>
public object? LeftContent
{
get => GetValue(LeftContentProperty);
set => SetValue(LeftContentProperty, value);
}
public static readonly StyledProperty<object?> RightContentProperty = AvaloniaProperty.Register<UrsaWindow, object?>(
nameof(RightContent));
/// <summary>
/// Gets or sets the content on the right side of the window.
/// </summary>
public object? RightContent
{
get => GetValue(RightContentProperty);
set => SetValue(RightContentProperty, value);
}
public static readonly StyledProperty<Thickness> TitleBarMarginProperty = AvaloniaProperty.Register<UrsaWindow, Thickness>(
nameof(TitleBarMargin));
/// <summary>
/// Gets or sets the margin of the title bar.
/// </summary>
public Thickness TitleBarMargin
{
get => GetValue(TitleBarMarginProperty);
set => SetValue(TitleBarMarginProperty, value);
}
/// <inheritdoc/>
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
var host = e.NameScope.Find<OverlayDialogHost>(PART_DialogHost);
if (host is not null) LogicalChildren.Add(host);
}
/// <summary>
/// Determines whether the window can close.
/// </summary>
/// <returns>A task that resolves to true if the window can close; otherwise, false.</returns>
protected virtual async Task<bool> CanClose()
{
return await Task.FromResult(true);
}
private bool _canClose = false;
/// <summary>
/// Handles the window closing event and determines whether the window should close.
/// </summary>
/// <param name="e">The event arguments for the closing event.</param>
protected override async void OnClosing(WindowClosingEventArgs e)
{
VerifyAccess();