c# - .net Avalonia 中更改窗口系统顶部栏背景颜色的更简单方法?

标签 c# .net-core avaloniaui

在 dotnet 的 Avalonia-UI 中框架。 我正在使用深色用户界面,并且我设法按照 this example 将所有内容变暗但有一件事:Windows 操作系统中窗口的系统顶部栏。

我在this issue in github中看到过我可以设置属性 HasSystemDecorations="false" 使其消失,但随后我必须自己实现顶部栏的拖动功能、标题、关闭、最大化、最小化等,当我只想更改背景颜色时,这很痛苦。

将窗口顶部栏更改为深色背景颜色的更简单方法是什么?

如果唯一的方法是使用HasSystemDecorations,那么使用关闭/最小化/最大化/拖动的常用功能来实现深色顶栏的最小示例是什么?

最佳答案

是的,您必须设置HasSystemDecorations="false"并实现您自己的标题栏。我在 Github 上有一个基本模板了解如何使用 0.10 版本和 Fluent 主题来执行此操作。

这实际上非常简单,因为 Avalonia 提供了很多方便的方法来实现这一点。

概述:

设置

ExtendClientAreaToDecorationsHint="True"
ExtendClientAreaChromeHints="NoChrome"
ExtendClientAreaTitleBarHeightHint="-1"

对于窗口,然后实现一个标题栏。例如,关闭按钮可能如下所示:

<Button Width="46"
        VerticalAlignment="Stretch"
        BorderThickness="0"
        Name="CloseButton"
        ToolTip.Tip="Close">
    <Button.Resources>
      <CornerRadius x:Key="ControlCornerRadius">0</CornerRadius>
    </Button.Resources>
    <Button.Styles>
      <Style Selector="Button:pointerover /template/ ContentPresenter#PART_ContentPresenter">
        <Setter Property="Background" Value="Red"/>
      </Style>
      <Style Selector="Button:not(:pointerover) /template/ ContentPresenter#PART_ContentPresenter">
        <Setter Property="Background" Value="Transparent"/>
      </Style>
      <Style Selector="Button:pointerover > Path">
        <Setter Property="Fill" Value="White"/>
      </Style>
      <Style Selector="Button:not(:pointerover) > Path">
        <Setter Property="Fill" Value="{DynamicResource SystemControlForegroundBaseHighBrush}"/>
      </Style>
    </Button.Styles>
    <Path Margin="10,0,10,0"
          Stretch="Uniform"
          Data="M1169 1024l879 -879l-145 -145l-879 879l-879 -879l-145 145l879 879l-879 879l145 145l879 -879l879 879l145 -145z"></Path>
  </Button>

如果您在控件上设置IsHitTestVisible="False",则可以将下面的窗口拖动到该区域中。因此,将整个标题栏包装在 DockPanel 中:

<DockPanel Background="Black"
           IsHitTestVisible="False"
           Name="TitleBarBackground"></DockPanel>

现在您显然仍然需要模仿按钮的行为。原则上可以像这样完成(再次查看上面的 Github 存储库的具体示例):

minimizeButton = this.FindControl<Button>("MinimizeButton");
maximizeButton = this.FindControl<Button>("MaximizeButton");
maximizeIcon = this.FindControl<Path>("MaximizeIcon");
maximizeToolTip = this.FindControl<ToolTip>("MaximizeToolTip");
closeButton = this.FindControl<Button>("CloseButton");
windowIcon = this.FindControl<Image>("WindowIcon");

minimizeButton.Click += MinimizeWindow;
maximizeButton.Click += MaximizeWindow;
closeButton.Click += CloseWindow;
windowIcon.DoubleTapped += CloseWindow;

private void CloseWindow(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
      Window hostWindow = (Window)this.VisualRoot;
      hostWindow.Close();
}

private void MaximizeWindow(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
     Window hostWindow = (Window)this.VisualRoot;

     if (hostWindow.WindowState == WindowState.Normal)
     {
           hostWindow.WindowState = WindowState.Maximized;
     }
     else
     {
           hostWindow.WindowState = WindowState.Normal;
     }
}

private void MinimizeWindow(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
      Window hostWindow = (Window)this.VisualRoot;
      hostWindow.WindowState = WindowState.Minimized;
}

现在最后一步是您需要根据窗口状态更改最大化按钮的图标。例如,如果您拖动最大化的窗口,它将自动恢复为向下状态,并且最大化按钮的图标需要更改。因此,您需要订阅主机窗口的窗口状态,这可以通过覆盖 Window.HandleWindowStateChanged 来完成。方法或通过执行以下操作:

private async void SubscribeToWindowState()
{
    Window hostWindow = (Window)this.VisualRoot;

    while (hostWindow == null)
    {
        hostWindow = (Window)this.VisualRoot;
        await Task.Delay(50);
    }

    hostWindow.GetObservable(Window.WindowStateProperty).Subscribe(s =>
    {
        hostWindow.Padding = hostWindow.OffScreenMargin;
        if (s != WindowState.Maximized)
        {
            maximizeIcon.Data = Avalonia.Media.Geometry.Parse("M2048 2048v-2048h-2048v2048h2048zM1843 1843h-1638v-1638h1638v1638z");
            maximizeToolTip.Content = "Maximize";
        }
        if (s == WindowState.Maximized)
        {
            maximizeIcon.Data = Avalonia.Media.Geometry.Parse("M2048 1638h-410v410h-1638v-1638h410v-410h1638v1638zm-614-1024h-1229v1229h1229v-1229zm409-409h-1229v205h1024v1024h205v-1229z");
            maximizeToolTip.Content = "Restore Down";
        }
    });
}

其实上面的代码片段还有一个细节,需要注意一下。至少在窗口上,最大化的窗口实际上比屏幕大。如果您不希望内容超出屏幕范围,则需要为窗口内的主控件添加边距。因此,hostWindowPadding 也会相应更改。 Avalonia 提供了一个 IWindowImpl.OffScreenMargin 属性,describes the margin around the window that is offscreen 。 您可以直接在窗口的 .axml

中绑定(bind)到此属性
<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        ExtendClientAreaToDecorationsHint="True"
        ExtendClientAreaChromeHints="NoChrome"
        ExtendClientAreaTitleBarHeightHint="-1"
        Padding="{Binding $self.OffScreenMargin}">

关于c# - .net Avalonia 中更改窗口系统顶部栏背景颜色的更简单方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65333019/

相关文章:

c# - 如何使用 Novell.Directory.Ldap.NETStandard 和 Simple Paged Results 控件在 Ldap 服务器上进行分页搜索?

c# - 时间线中可调整大小的片段 : bind segment size to view model

wpf - Avalonia Ui 相当于 ImageResource

c# - MVC HttpGet 和 HttpPost

c# - 模型 MVC 5 的 session 数据

.net-core - 升级到 2.1 后,dotnet core cpu 利用率发生了巨大变化

c# - 如何在 Avalonia 应用程序中为 OpenFolderDialog 设置标题?

c# - TcpClient.Available 优化

c# - 类库中文件的路径

asp.net-core - .net core 2 中 fuslogvw 的替代品是什么?