乘风破浪,遇见最佳跨平台跨终端框架.Net Core/.Net生态 - WPF应用插上Windows 11流畅设计系统的翅膀,ModernWpf=>WPF UI

前言

谈到Windows 11流畅设计系统(Fluent Design System),我们不得不提到Mica材质,有了它才能算现代的流畅性UI。

image

前戏方案(ModernWpf)

之前聊过通过微软未公开的DWM文档来实现它,但是没多久系统一更新就失效了,较早使用ModernWpf的版本可见历史博文:乘风破浪,遇见最美Windows 11之现代Windows桌面应用开发 - Microsoft Edge WebView2运行时 - 尝试WPF上实现Windows 11的Mica风格,笔者重新试过这个方案,效果不是很完美。

image

虽然已经它也有公布Windows 11 22523+之后的改进方案,但是效果仍然不理想,具体示例可见:dongle-the-gadget/SystemBackdropTypes

image

其核心还是通过"DwmApi.dll"来实现枚举赋值调用,也还是可以做到Mica效果的。

public static class Methods
{
    [DllImport("DwmApi.dll")]
    static extern int DwmExtendFrameIntoClientArea(
        IntPtr hwnd,
        ref ParameterTypes.MARGINS pMarInset);

    [DllImport("dwmapi.dll")]
    static extern int DwmSetWindowAttribute(IntPtr hwnd, ParameterTypes.DWMWINDOWATTRIBUTE dwAttribute, ref int pvAttribute, int cbAttribute);

    public static int ExtendFrame(IntPtr hwnd, ParameterTypes.MARGINS margins)
        => DwmExtendFrameIntoClientArea(hwnd, ref margins);

    public static int SetWindowAttribute(IntPtr hwnd, ParameterTypes.DWMWINDOWATTRIBUTE attribute, int parameter)
        => DwmSetWindowAttribute(hwnd, attribute, ref parameter, Marshal.SizeOf<int>());
}
public class ParameterTypes
{
    /*
    [Flags]
    enum DWM_SYSTEMBACKDROP_TYPE
    {
        DWMSBT_MAINWINDOW = 2, // Mica
        DWMSBT_TRANSIENTWINDOW = 3, // Acrylic
        DWMSBT_TABBEDWINDOW = 4 // Tabbed
    }
    */

    [Flags]
    public enum DWMWINDOWATTRIBUTE
    {
        DWMWA_USE_IMMERSIVE_DARK_MODE = 20,
        DWMWA_SYSTEMBACKDROP_TYPE = 38
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct MARGINS
    {
        public int cxLeftWidth;      // width of left border that retains its size
        public int cxRightWidth;     // width of right border that retains its size
        public int cyTopHeight;      // height of top border that retains its size
        public int cyBottomHeight;   // height of bottom border that retains its size
    };
}
var flag = 2;
SetWindowAttribute(
new WindowInteropHelper(this).Handle,
DWMWINDOWATTRIBUTE.DWMWA_SYSTEMBACKDROP_TYPE,
flag);

最新方案(WPF UI)

简介

image

WPF UI是一套WPF界面库,一个简单的方法来使你的WPF应用程序跟上现代设计的趋势。该库改变了基本的元素,如Page, ToggleButtonList,还包括了额外的控件,如Navigation, NumberBox, DialogSnackbar

视觉效果如下:

image

image

image

参考示例

官方还是给了不错的示例./wpfui/tree/main/src

image

简单使用

依赖包

https://www.nuget.org/packages/wpf-ui/

dotnet add package wpf-ui

image

App.xaml中引入下样式字典资源: ui:ThemesDictionaryui:ControlsDictionary

<Application 
    x:Class="ConvertHybirdContent.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Startup="OnStartup"
    xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ui:ThemesDictionary Theme="Light" />
                <ui:ControlsDictionary />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

接下来在MainView.xaml窗体的Window也要改造下,从原来的Window换成ui:UiWindow

<ui:UiWindow 
    x:Class="SuperConvert.Hybirding.Interface.Pages.MainView"
    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:ui="http://schemas.lepo.co/wpfui/2022/xaml"
    mc:Ignorable="d"
    Height="600"
    Width="1024"
    WindowStartupLocation="CenterScreen"
    ExtendsContentIntoTitleBar="True"
    WindowBackdropType="Mica"
    WindowCornerPreference="Round"
    >

</ui:UiWindow>

记得同步换掉MainView.xaml.cs继承的。

/// <summary>
/// MainView.xaml 的交互逻辑
/// </summary>
public partial class MainView : UiWindow
{

}

新增支持窗体设置

ui:UiWindow这里可以设置三个属性:

  • 扩展内容到标题栏(ExtendsContentIntoTitleBar),开启后会覆盖原来窗体的标题栏,可以重写界面。
  • 窗体背景效果类型(WindowBackdropType),这里可以设置为Mica代表Windows 11 Mica效果,淡雅的味道,其它可选的值还有None代表无效果、Auto代表自动模式,实测白茫茫一片、Acrylic代表亚克力效果,熟悉的半透明磨砂玻璃效果,Windows 10老基友的最爱、Tabbed代表Windows 11 Tabbed效果,看来接近亚克力,但是要模糊更多,不透。
  • 窗体圆角样式(WindowCornerPreference),这里可以设置为Round代表Windows 11圆角窗体,其它可选值还有RoundSmall代表更数值更小的圆角,DoNotRound代表没有圆角,没错其实就是直角。

窗体背景效果类型(WindowBackdropType)定义:

/// <summary>
/// Collection of fluent background types.
/// </summary>
public enum BackgroundType
{
    /// <summary>
    /// Unknown background type.
    /// </summary>
    Unknown,

    /// <summary>
    /// No backdrop effect.
    /// </summary>
    None,

    /// <summary>
    /// Sets <c>DWMWA_SYSTEMBACKDROP_TYPE</c> to <see langword="0"></see>.
    /// </summary>
    Auto,

    /// <summary>
    /// Windows 11 Mica effect.
    /// </summary>
    Mica,

    /// <summary>
    /// Windows Acrylic effect.
    /// </summary>
    Acrylic,

    /// <summary>
    /// Windows 11 wallpaper blur effect.
    /// </summary>
    Tabbed
}

窗体圆角样式(WindowCornerPreference)定义:

/// <summary>
/// Ways you can round windows.
/// </summary>
public enum WindowCornerPreference
{
    /// <summary>
    /// Determined by system or application preference.
    /// </summary>
    Default,

    /// <summary>
    /// Do not round the corners.
    /// </summary>
    DoNotRound,

    /// <summary>
    /// Round the corners.
    /// </summary>
    Round,

    /// <summary>
    /// Round the corners slightly.
    /// </summary>
    RoundSmall
}

监听系统主题变化

考虑到用户会切浅色和暗色主题,那么能不能自动响应呢?答案是可以的。

我们在MainView.xaml.cs构造函数中的窗体Loaded事件来监听变化,并且自动响应。

/// <summary>
/// MainView.xaml 的交互逻辑
/// </summary>
public partial class MainView : UiWindow
{
    public MainView()
    {
        InitializeComponent();
        Loaded += (sender, args) =>
        {
            Wpf.Ui.Appearance.Watcher.Watch(
                this,
                Wpf.Ui.Appearance.BackgroundType.Mica,
                true
            );
        };
    }
}

看下效果

image

参考

posted @ 2022-12-06 23:36  TaylorShi  阅读(2178)  评论(0编辑  收藏  举报