在dotnet的Avalonia-UI框架中。我使用的是一个深色的用户界面,我设法按照this example把所有的东西都变暗了,但有一件事是这样的: Windows操作系统的系统顶栏。
我在this issue in github中看到,我可以设置属性HasSystemDecorations="false"
使其消失,但随后我必须实现自己的顶部栏,并使用拖动功能、标题、关闭、最大化、最小化等,当我只想要更改背景颜色时,这是一件痛苦的事情。
将窗口顶部栏更改为深色背景色更简单的方法是什么?
如果唯一的方法是使用HasSystemDecorations
,那么实现带有关闭/最小化/最大化/拖动的常见功能的深色顶部栏的最小示例是什么?
发布于 2020-12-19 17:15:25
是的,你必须设置HasSystemDecorations="false"
并实现你自己的标题栏。我在Github上有一个基本的模板,告诉你如何使用0.10版本和流畅的主题来做这件事。
这实际上非常简单,因为Avalonia提供了许多方便的方法来实现这一点。
概述:
设置
ExtendClientAreaToDecorationsHint="True"
ExtendClientAreaChromeHints="NoChrome"
ExtendClientAreaTitleBarHeightHint="-1"
然后实现一个标题栏。例如,close按钮可能如下所示:
<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;
}
现在,最后一步是您需要根据窗口状态更改最大化按钮的图标。例如,如果您拖动最大化的窗口,它将自动向下恢复,并且最大化按钮的图标需要更改。因此,您需要订阅主机窗口的窗口状态,这可以像这样完成:
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 =>
{
if (s != WindowState.Maximized)
{
maximizeIcon.Data = Avalonia.Media.Geometry.Parse("M2048 2048v-2048h-2048v2048h2048zM1843 1843h-1638v-1638h1638v1638z");
hostWindow.Padding = new Thickness(0,0,0,0);
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");
hostWindow.Padding = new Thickness(7,7,7,7);
maximizeToolTip.Content = "Restore Down";
}
});
}
实际上,在上面的代码片段中,还有一个细节需要注意。至少在windows上,最大化的窗口实际上比屏幕要大。如果你不想让你的内容超出屏幕的边界,你需要在窗口内的主控件上添加一个边距。因此,hostWindow
的Padding
会相应地改变。
https://stackoverflow.com/questions/65333019
复制相似问题