乘风破浪,遇见最佳跨平台跨终端框架.Net Core/.Net生态 - WPF应用插上Windows 11流畅设计系统的翅膀,ModernWpf=>WPF UI
前言
谈到Windows 11流畅设计系统(Fluent Design System
),我们不得不提到Mica材质,有了它才能算现代的流畅性UI。
前戏方案(ModernWpf)
之前聊过通过微软未公开的DWM文档来实现它,但是没多久系统一更新就失效了,较早使用ModernWpf的版本可见历史博文:乘风破浪,遇见最美Windows 11之现代Windows桌面应用开发 - Microsoft Edge WebView2运行时 - 尝试WPF上实现Windows 11的Mica风格,笔者重新试过这个方案,效果不是很完美。
虽然已经它也有公布Windows 11 22523+之后的改进方案,但是效果仍然不理想,具体示例可见:dongle-the-gadget/SystemBackdropTypes
其核心还是通过"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)
简介
WPF UI是一套WPF界面库,一个简单的方法来使你的WPF应用程序跟上现代设计的趋势。该库改变了基本的元素,如Page
, ToggleButton
或List
,还包括了额外的控件,如Navigation
, NumberBox
, Dialog
或Snackbar
。
视觉效果如下:
参考示例
官方还是给了不错的示例./wpfui/tree/main/src
简单使用
依赖包
dotnet add package wpf-ui
在App.xaml
中引入下样式字典资源: ui:ThemesDictionary
、ui: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
);
};
}
}