mcpField
W
winui-design

winui-design

github.com/microsoft设计与 UI490260 次安装3 周前更新
代码仓库

关于 winui-design

面向 WinUI 开发的界面设计技能,借助 WinApp CLI 查找示例与 API,并提供控件选择、窗口尺寸、XAML、主题和无障碍方面的指导。

主要功能

  1. 01编码前搜索 WinUI 示例
  2. 02按项目引用核验 API
  3. 03按需求映射平台控件
  4. 04窗口尺寸与 XAML 指引
  5. 05主题与无障碍检查

适用场景

  1. 01为新 WinUI 页面选择控件
  2. 02根据还原的包检查 API
  3. 03避免绑定与布局错误
  4. 04检查主题和界面无障碍

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/microsoft/win-dev-skills --skill winui-design

安装后在 Claude Code 中输入/winui-design确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
brushes-and-icons.md
layout-review.md
theme-accessibility.md

详细介绍

编写 XAML 前搜索示例

此工作流需要 WinApp CLI 0.7+。使用 winapp find-ui 查找有依据的控件和示例。先查找,再编码:

winapp find-ui "<focused feature>"                    # compact matches + scenario IDs
winapp find-ui --id <scenario-id>                    # full XAML/C# + prerequisite notes
winapp find-ui --id <id-1> --id <id-2> --json        # batch, structured output
winapp find-ui --list                                # browse all default-source scenarios
winapp find-ui "<feature>" --refresh                 # force a corpus refresh

默认搜索涵盖 WinUI Gallery、Windows Community Toolkit 和精选核心模式。Reactor 的纯 C#/MVU 示例需通过 --source reactor 显式启用;仅在 Reactor 项目中使用。WinApp CLI 会获取并缓存 Gallery/Toolkit/Reactor 语料库,而核心模式可离线使用。

根据已还原的项目验证 API

在编写 API 假设前,请从已还原的应用项目目录运行命令,确保 winapp find-api 使用该项目的确切引用,而非某个示例中可能更新的包版本:

winapp find-api InfoBar --json --project-dir .
winapp find-api check-property InfoBar Severity IsOpen Message Title --json --project-dir .
winapp find-api members NavigationView --filter selected --json --project-dir .

选择多个项目时,使用 --project-dir <app-directory>(默认为当前工作目录)或 --project <name>,不能同时使用两者。从仓库根目录或同级项目发起未指定范围的查询,可能会查到错误的 API 范围。--project sdk 只搜索已安装的机器 SDK,不搜索应用的 NuGet 引用。如果结果看起来过时,请先检查还原和项目选择,再刷新。使用 winapp find-api --help 查看发现/索引命令,不要凭记忆猜测 API;使用 find-ui 查找用法模式。

应用形态参考

开始布局页面前,先选择最接近的已发布应用形态:

应用类型参考控件参考应用
设置 / 配置工具NavigationView 左侧导航 + SettingsCard / SettingsExpanderWindows 设置、Slack
文档 / 会话编辑器TabView + 全出血内容、简洁界面Windows Terminal、VS Code、Notepad
层级浏览器TreeView + ListView + BreadcrumbBar文件资源管理器、Outlook
开发者工具 / 仪表板NavigationView + 卡片布局Dev Home、GitHub Desktop
单一用途实用工具模式切换器 + 紧凑网格计算器、截图工具
媒体 / 画布 / 主视觉使用主视觉区域和浮动命令的 Grid,不使用 NavigationView照片、Spotify、Clipchamp

常用控件速查表

编写 XAML 前,将需求映射到平台控件。这些映射旨在避免沿用其他框架的习惯(WPF DataGrid、Web <select>、HTML <input type=date>):

  • 导航: 2–7 个分区 → NavigationView;文档/会话选项卡 → TabView;面包屑路径 → BreadcrumbBar;2–3 种模式 → SelectorBar。
  • 数据显示: 垂直列表 → ListView;平铺/网格 → GridView 或 ItemsRepeater + UniformGridLayout;层级结构 → TreeView;表格数据 → 使用基于 Grid 的 ItemTemplate 的 ListView,并在上方放置标题 Grid(WinUI 没有 DataGrid;不要默认使用 CommunityToolkit.WinUI.Controls.DataGrid——其列无法使用 x:Bind);主从视图 → ListView + 详细信息 Grid。
  • 输入: 文本 → TextBox;数字 → NumberBox;搜索 → AutoSuggestBox;日期 → CalendarDatePicker;布尔值 → ToggleSwitch;从 2–3 项中选一项 → RadioButtons;从 4 项或更多中选一项 → ComboBox。
  • 反馈: 阻塞式决策 → ContentDialog;上下文操作 → Flyout / MenuFlyout;引导 / 提示 → TeachingTip;内联状态 / 异步进度 → InfoBar;系统通知 → AppNotification。

如果以上映射不适用,请先运行 winapp find-ui "<intent>",再自行尝试。

窗口尺寸(WinUI 3 特有)

WinUI 3 没有 SizeToContent。 如果不显式设置尺寸,Windows 会默认将主窗口设为约 1024×768,这对大多数实用工具来说都太大了。请在 MainWindow 的构造函数中设置尺寸。

参考标准。 宽度 = 最宽一行的宽度 + 48 像素边距,再向上取整到最接近的 20 的倍数。高度 = 32(标题栏)+ Σ(各行高度)+ Σ(间距)+ 48 像素边距,再向上取整到 20 的倍数。向上取整——内容被裁切比窗口稍微偏宽更糟。合理范围(请根据参考标准自行推导):

  • 单一用途的实用工具 → 宽约 440–560
  • 表单 / 单页工具 → 宽约 600–800,高约 640–800
  • 多窗格(导航 + 内容)→ 宽约 1100–1300,高约 720–840
  • 文档 / 画布 / 媒体编辑器 → 宽 1280 以上

AppWindow.Resize 接受的是物理像素,而不是 DIP——请乘以显示器的 DPI 缩放比例。构造函数中 XamlRoot.RasterizationScale 为 null,且在 AppWindow.Move 后会过时,因此 [DllImport] GetDpiForWindow 是最简洁的做法:

using Microsoft.UI;
using Microsoft.UI.Windowing;
using System.Runtime.InteropServices;
using Windows.Graphics;

public sealed partial class MainWindow : Window
{
    [DllImport("user32.dll")]
    private static extern uint GetDpiForWindow(IntPtr hWnd);

    public MainWindow()
    {
        InitializeComponent();
        var hwnd  = Win32Interop.GetWindowFromWindowId(AppWindow.Id);
        var scale = GetDpiForWindow(hwnd) / 96.0;
        // widthDip / heightDip come from the rubric above — derive, don't copy.
        AppWindow.Resize(new SizeInt32((int)(widthDip * scale), (int)(heightDip * scale)));
    }
}

不要通过设置根 Grid 的 Width/Height 来调整窗口尺寸——这样裁切的是内容,而不是窗口。

XAML 易踩的坑(否则你会把有问题的代码交付出去)

检查生效的 x:Bind 模式

除非继承的 x:DefaultBindMode 修改了默认值,否则 x:Bind 默认为 OneTime。动态数据应使用 OneWay/TwoWay 并提供更改通知;显式指定的 Mode 会覆盖继承的默认值。稳定的命令 / 事件绑定无需统一重写模式。


<TextBlock Text="{x:Bind Vm.Status}" />

<TextBlock Text="{x:Bind Vm.Status, Mode=OneWay}" />

在页面 / 窗口中,x:Bind 会针对代码隐藏解析(例如其 Vm 属性),而不是针对 DataContext。请在有类型的 DataTemplates 上使用 x:DataType,不要在 Page 上用它来设置 VM。运行时 {Binding}/DisplayMemberPath 也可能合适;对于 AOT,其源类可能需要添加 partial 并标注 [WinRT.GeneratedBindableCustomProperty]。请参阅 winui-packaging 的 references/sourcegen-patterns.md,不要将所有运行时绑定都视为不受支持。

TextBox 双向绑定需要 UpdateSourceTrigger=PropertyChanged
<TextBox Text="{x:Bind Vm.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

默认触发器对 TextBox.Text 来说是 LostFocus(大多数其他属性的默认值为 PropertyChanged)。每次按键后都不会更新 VM,因此 UIA 键盘模拟测试(WinAppDriver SendKeys 等)如果在输入后立即断言,就会在焦点移动前看到过时的 VM 状态。

在 C# 中使用静态 setter 设置附加属性,而不是使用初始化器
using Microsoft.UI.Xaml.Automation;

// ❌ WRONG — does not compile. CS0117: 'Button' does not contain a definition for 'AutomationProperties'.
// AutomationProperties is a static class of attached-property accessors, not an instance member.
var btn = new Button { AutomationProperties = { AutomationId = "BtnSave" } };

// ✅ CORRECT
var btn = new Button { Content = "Save" };
AutomationProperties.SetAutomationId(btn, "BtnSave");
AutomationProperties.SetName(btn, "Save button");
Grid.SetRow(btn, 1);
ToolTipService.SetToolTip(btn, "Save the current document");
Converter={x:Null} 会导致 x:Bind 在运行时崩溃

{x:Bind} 要求 Converter 使用 {StaticResource} 查找。Converter={x:Null} 虽然可以编译,但生成的代码会调用 LookupConverter(""),该调用返回 null,随后代码会对其解引用——首次激活绑定时就会出现 Resource Dictionary Key can only be String-typed / NullReferenceException。如果不需要转换器,请完全省略该属性。

优先使用 x:Bind 静态函数,而不是 IValueConverter
// MainPage.xaml.cs
public static Visibility BoolToVisibility(bool v) => v ? Visibility.Visible : Visibility.Collapsed;
public static Visibility InvertBoolToVisibility(bool v) => v ? Visibility.Collapsed : Visibility.Visible;
public static bool Not(bool v) => !v;
<TextBlock Visibility="{x:Bind local:MainPage.BoolToVisibility(Vm.IsLoading), Mode=OneWay}" />
<Button   IsEnabled="{x:Bind local:MainPage.Not(Vm.IsLoading), Mode=OneWay}" />
Acrylic 和 ThemeShadow 的渲染规则
  • Border 和 Control 的 BackgroundSizing 默认值都是 InnerBorderEdge,这会将 Acrylic 正确裁切到内侧描边。风险与直觉相反:带描边的 Acrylic 表面不要将其改为 OuterBorderEdge——这会使材质溢出描边。
  • ThemeShadow 会根据投影对象的 Translation Z 投射阴影。Microsoft 推荐的高度为:工具提示使用 16,弹出 / Flyout UI 使用 32,对话框使用 128——请根据表面类型选择。对于非弹出式投影对象,请将阴影应落到的表面添加到 ThemeShadow.Receivers;否则阴影无处可落,看起来会像被裁切一样。

主题规则(简版)

  • 在使用位置使用 {ThemeResource ...}(切换主题时会更新)。在 ThemeDictionaries 中使用 {StaticResource} 定义主题专属资源;SystemAccentColor / SystemColor* 是例外,仍使用 {ThemeResource}。
  • 自定义主题字典必须明确涵盖 Light、Dark 和 HighContrast — 绝不能使用 Default。
  • 按用途命名资源(CardBackgroundBrush、DangerTextBrush),而不是按色相命名。
  • 浅色/深色主题可用 ≠ 高对比度主题可用。请单独在对比度主题中测试。
  • 除非你的应用已全面提供适配系统的画笔,否则绝不要设置 HighContrastAdjustment="None"。

反模式

❌ 不要✅ 改为
不假思索地把每个应用都做成左侧 NavigationView在轮廓表中选最接近的一行;主视觉、文档和实用工具布局同样适用
把品牌色或着色背景视为不符合规范覆盖 SystemAccentColor 或使用着色的 DesktopAcrylicBackdrop,正是 Microsoft 自家第一方应用实现差异化的方式
在过大的窗口中放置很小的内容区域将窗口大小调整到与内容相适应(参见 窗口大小调整),或让内容填满可用空间
手动构建自定义胶囊式/分段式标签切换器使用 NavigationView Top 或 SelectorBar
两列等宽 50/50 分割,其中一个窗格仅用于布局结构结构窗格使用固定尺寸,内容区域灵活调整 — 仅当布局轮廓确实包含结构窗格时才采用
硬编码颜色字面值(#RRGGBB、White)使用按语义命名的 {ThemeResource} 画笔
在 ListView / GridView 外包一层 ScrollViewer集合控件本身已有滚动功能 — 为其指定受限高度
为标准控件自定义 ControlTemplate使用内置控件 + 轻量样式覆盖
仅用占位文本作为字段标签始终提供可见标签
在小屏幕上隐藏必需命令,且不提供其他入口使用溢出菜单、次级界面或响应式提升规则
使用模态 ContentDialog 显示非阻塞提示使用 TeachingTip、InfoBar 或内联状态
不经确认就触发破坏性操作(删除/丢弃/重置)使用 ContentDialog,主操作按钮以动词命名,次要按钮为“取消”;在正文中显示项目标识信息(名称、数量)
在 ListView / GridView 已适用时仍自定义列表控件使用平台集合控件 + 虚拟化

仅当以下条件全部满足时才构建自定义 UI:没有适用的平台/Gallery/Toolkit 控件;你将实现键盘、焦点、UI 自动化、主题资源、高对比度和响应式行为;你有默认/悬停/按下/禁用/选中/聚焦/错误状态的规范;你已使用键盘和对比度主题完成测试。

参考资料(按需加载)

文件在以下情况下加载…
references/brushes-and-icons.md按用途查找画笔键、在 Icon / IconSource 插槽之间做选择,或在 FontIcon / SymbolIcon / PathIcon 等图标中做选择时。
references/theme-accessibility.md编写主题字典、自定义画笔/样式/模板或高对比度支持时。
references/layout-review.md审查响应式行为、断点,或数据驱动页面的空内容/加载中/错误状态覆盖时。

评论

支持 Markdown