wpf、Avalonia标题栏

烂柯 发布于 2023-11-19 265 次阅读


一、概述

​ 桌面应用,设计要求不同的标题颜色并且窗口有一定的阴影效果。开始是基于wpf做的应用,后续因为有系统需求所以迁移至avaloniaUi,通过查阅资料实现了需求效果,所以记录下方便自己后续查阅。

二、WPF标题栏

​ 通过类WindowChrome使你能够将Windows Presentation Foundation (WPF) 内容扩展到通常为操作系统的窗口管理器保留的窗口的非工作区。主要设置两个属性 WindowStyle、ResizeBorderThickness,也可以通过模板进行修改设置。

MainWindow.xaml

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        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"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" 
        Height="450" Width="800"
        WindowStyle="None">
    <WindowChrome.WindowChrome>
        <WindowChrome ResizeBorderThickness="2"/>
    </WindowChrome.WindowChrome>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid Grid.Row="0" Background="Gray" MouseDown="Grid_MouseDown">
            <TextBlock Text="MainWindow"/>
        </Grid>
        <Grid Grid.Row="1"></Grid>
    </Grid>
</Window>

MainWindow.xaml.cs

using System.Windows;
using System.Windows.Input;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Grid_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (e.LeftButton!=MouseButtonState.Pressed) 
                return;
            this.DragMove();
        }
    }
}

三、AvaloniaUi标题栏

特别注意:WindowStateShowInTaskbar属性同时出现,一定一定要将WindowState属性放置在ShowInTaskbar属性之前。不然win11左下角会有窗,并且初始化时重新配置WindowState属性,不然win7左下角会有窗口,如下

<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"
        x:Class="MainWindow"
        WindowState="Minimized"
        CanResize="False"
        Topmost="True"
        IsVisible="True"
        ShowInTaskbar="False"
        ExtendClientAreaToDecorationsHint="True"
        ExtendClientAreaChromeHints="NoChrome"
        ExtendClientAreaTitleBarHeightHint="-1"
        SystemDecorations="None">
</Window>
...
public MainWindow()
{
    InitializeComponent();
    WindowState = WindowState.Minimized
}
...

方式一、属性配置

主要设置属性:

ExtendClientAreaTitleBarHeightHint:设置为0隐藏标题栏按钮(最大最小化、关闭)。

注:windows10 按钮看不见但依旧有效且无阴影效果

ExtendClientAreaToDecorationsHint:内容扩展至标题栏

MainWindow.axaml

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="using:AvaloniaApplication1.ViewModels"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:views="clr-namespace:AvaloniaApplication1.Views"
        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
        x:Class="AvaloniaApplication1.Views.MainWindow"
        Icon="/Assets/avalonia-logo.ico"
        Title="AvaloniaApplication1"
        ExtendClientAreaTitleBarHeightHint="0"
        ExtendClientAreaToDecorationsHint="True">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid Grid.Row="0" Background="Gray" PointerPressed="Grid_PointerPressed">
            <TextBlock Text="MainWindow"/>
        </Grid>
        <Grid Grid.Row="1">
            <views:MainView />
        </Grid>
    </Grid>
</Window>

MainWindow.axaml.cs

using Avalonia.Controls;

namespace AvaloniaApplication1.Views;

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Grid_PointerPressed(object? sender, Avalonia.Input.PointerPressedEventArgs e)
    {
        BeginMoveDrag(e);
    }
}

方式二、模板控件(自定义窗体)

通过模板控件统一窗体样式,并添加window控件基础类统一基础事件

BaseWindow.axaml

<Styles xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:controls="using:AvaloniaApplication1.Views">
  <Design.PreviewWith>
    <controls:BaseWindow Height="200" Width="400" />
  </Design.PreviewWith>
  <Style Selector="Window">
      <Setter  Property="SystemDecorations" Value="None"/>
      <Setter Property="Template">
      <ControlTemplate>
        <Border BorderBrush="#DCDCDC" BorderThickness="1" Background="White"
                Height="{Binding BorderHeight,RelativeSource={RelativeSource AncestorType=Window,Mode=FindAncestor}}"
                Width="{Binding BorderWidth,RelativeSource={RelativeSource AncestorType=Window,Mode=FindAncestor}}">
          <Border.Effect>
            <DropShadowEffect BlurRadius="30" Opacity="0.2" Color="black"/>
          </Border.Effect>
          <Grid>
            <Grid.RowDefinitions>
              <RowDefinition Height="30"/>
              <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Grid Grid.Row="0" Name="TitlePanel" Background="Gray">
              <Image Source="{Binding TitleIcon}" Height="25" Width="25"/>
              <TextBlock Text="{TemplateBinding Title}"
                         Margin="5,0,0,0"
                         VerticalAlignment="Center"/>
            </Grid>
            <ContentPresenter Grid.Row="1" Content="{TemplateBinding Content}"/>
          </Grid>
        </Border>
      </ControlTemplate>
    </Setter>
  </Style>
</Styles>

BaseWindow.axaml.cs

{
    public class BaseWindow : Window
    {
        //有这个才能渲染出来
        protected override Type StyleKeyOverride => typeof(Window);
        protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
        {
            base.OnApplyTemplate(e);
            Grid? titlePanel = e.NameScope.Find<Grid>("TitlePanel");
            if (titlePanel != null) titlePanel.PointerPressed += Grid_PointerPressed;
        }
        private void Grid_PointerPressed(object? sender, Avalonia.Input.PointerPressedEventArgs e)
        {
            BeginMoveDrag(e);
        }

        public Bitmap? TitleIcon
        {
            get
            {
                if (Icon == null) return null;
                Stream stream = new MemoryStream();
                Icon.Save(stream);
                return new Bitmap(stream);
            }
        }
        //使用时一定要设置宽度
        public new double Width
        {
            get => GetValue(WidthProperty);
            set
            {
                SetValue(WidthProperty, GetWidthHeightValue(value));
                BorderWidth = value;
            }
        }
        //使用时一定要设置高度
        public new double Height
        {
            get => GetValue(HeightProperty);
            set
            {
                SetValue(HeightProperty, GetWidthHeightValue(value));
                BorderHeight = value;
            }
        }

        /// <summary>
        /// 获取宽高值,仅win10预留阴影位置
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        private double GetWidthHeightValue(double value)
        {
            return Environment.OSVersion.Platform == PlatformID.Win32NT && Environment.OSVersion.Version.Major == 10 && Environment.OSVersion.Version.Build < 2200 ? value + 40 : value;
        }

        public double BorderHeight { get; set; }
        public double BorderWidth { get; set; }
    }
}

App.axaml 引用模板样式

<Application xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Class="AvaloniaApplication1.App"
             RequestedThemeVariant="Light">
             <!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->

    <Application.Styles>
        <FluentTheme />
        <StyleInclude Source="/Views/BaseWindow.axaml"/>
    </Application.Styles>
</Application>
烂柯

最后更新于 2024-01-16