news 2026/9/17 14:05:42

WinUI TeachingTip 控件完整实战指南:半持久化内容丰富的 Flyout 交互设计

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
WinUI TeachingTip 控件完整实战指南:半持久化内容丰富的 Flyout 交互设计

WinUI TeachingTip 控件完整实战指南:半持久化内容丰富的 Flyout 交互设计

【免费下载链接】microsoft-ui-xamlWinUI: a modern UI framework with a rich set of controls and styles to build dynamic and high-performing Windows applications.项目地址: https://gitcode.com/GitHub_Trending/mi/microsoft-ui-xaml

TeachingTip 是 WinUI(microsoft-ui-xaml)中一种半持久化(semi-persistent)、内容丰富的浮出控件,用于向用户告知、提醒或教学新功能与重要更新。它既能以尖角(tail)精确指向某个 UI 元素,也能作为无目标提示悬浮在窗口边缘。本文将以仓库中 TeachingTipSpec.md 为核心骨架,结合 控件源码 与 IDL 定义,完整讲解 TeachingTip 的适用场景、13 种放置模式、按钮/图标/Hero 内容定制、轻触关闭(light-dismiss)、取消与延迟关闭事件,以及无障碍与键盘/游戏手柄导航细节,帮助你直接上手编写可运行的高质量引导提示。

什么是 TeachingTip,何时该用它

原文定义:A teaching tip is a semi-persistent and content-rich flyout that provides contextual information.

TeachingTip 的典型用途是将用户注意力聚焦到新功能、重要更新或非必需但能改善体验的选项上,或者教会用户如何完成某个任务。它可以:

  • 通过尖角(tail)精确指向屏幕上的某个 UI 元素,增强上下文清晰度;
  • 完全不设置 Target,作为无目标提示悬浮在窗口边缘;
  • 由用户显式关闭(点击右上角 X 或底部 Close 按钮),或以**轻触关闭(light-dismiss)**方式在用户滚动或点击其他区域时自动消失。

什么时候不应该用

因为 TeachingTip 是瞬态的,所以不推荐用它提示错误或重要的状态变更——这类信息应该使用 ContentDialog、InfoBar 等更持久、更需要用户确认的控件。原文档对此有明确说明,这也是选择控件时的第一判断标准。

推荐使用原则(来自原文档 Recommendations)

  • 提示内容应是非关键的:不要在其中放置对应用体验至关重要的信息或选项;
  • 避免过于频繁地弹出提示:将提示分散在较长的会话或多个会话中,才能让每条提示获得用户的独立关注;
  • 保持简短、主题清晰:研究表明用户平均只阅读 3-5 个单词、理解 2-3 个单词,就会决定是否与提示交互;
  • 对于预测会使用游戏手柄(gamepad)输入的应用,务必参考 XY 焦点导航相关设计,并在所有可能的 UI 配置下逐一测试每条提示的手柄可达性(仓库源码TeachingTipAutomationPeer与焦点处理也印证了这一点,详见后文"输入与无障碍")。

基础用法:创建一个 TeachingTip

原文档提供了两种声明方式:放置在 ResourceDictionary / 资源中,或直接放在元素树(element tree)中。两种方式行为完全一致——TeachingTip 只在IsOpen = true时显示,不占据布局空间。

有目标(Targeted)的 TeachingTip

以下 XAML 演示默认外观:通过Target属性绑定到按钮,标题与副标题随之显示:

<Button x:Name="SaveButton" Content="Save"> <Button.Resources> <controls:TeachingTip x:Name="AutoSaveTip" Target="{x:Bind SaveButton}" Title="Save automatically" Subtitle="When you save your file to OneDrive, we save your changes as you go - so you never have to."> </controls:TeachingTip> </Button.Resources> </Button>

在代码后置中控制显示时机(例如首次启动时展示一次):

public MainPage() { this.InitializeComponent(); if (!HaveExplainedAutoSave()) { AutoSaveTip.IsOpen = true; SetHaveExplainedAutoSave(); } }

无目标(Non-targeted)的 TeachingTip

当提示内容与屏幕上某个元素无关时,不设置Target,提示将相对于 XamlRoot 的边缘显示;同时通过TailVisibility="Collapsed"隐藏尖角:

<Button x:Name="SaveButton" Content="Save" /> <controls:TeachingTip x:Name="AutoSaveTip" Title="Saving automatically" Subtitle="We save your changes as you go - so you never have to."> </controls:TeachingTip>

从 TeachingTip.h 源码可以看到,控件内部维护了m_target引用,并在UpdateTail()中处理"无目标且 TailVisibility 非 Visible 时折叠尖角"的逻辑;DetermineEffectivePlacement()则根据m_target是否存在分流到DetermineEffectivePlacementTargeted()/DetermineEffectivePlacementUntargeted()两套完全不同的放置算法。

放置模式(PreferredPlacement):13 种模式与回退策略

TeachingTip 复刻了 Flyout 的FlyoutPlacementMode行为,通过TeachingTipPlacementMode枚举实现(完整枚举见 TeachingTip.idl):

enum TeachingTipPlacementMode { Auto, Top, TopRight, TopLeft, Right, RightTop, RightBottom, Bottom, BottomRight, BottomLeft, Left, LeftTop, LeftBottom, Center, };

默认行为

  • 有目标:默认尝试放置在目标上方
  • 无目标:默认放置在 XamlRoot底部居中
  • 与 Flyout 相同:若首选放置模式空间不足,将自动选择其他模式

有目标的放置语义

放置模式第一个词表示提示将居中对齐于目标的哪一侧,尖角(tail)始终位于该侧的中心并指向目标;若存在第二个词,则提示主体向该方向偏移。例如BottomLeft表示提示出现在目标下方、主体向左偏移。Center是唯一的特例:尖角指向目标中心,提示主体居中于目标上半部分。

<Button x:Name="SaveButton" Content="Save"> <Button.Resources> <controls:TeachingTip x:Name="AutoSaveTip" Target="{x:Bind SaveButton}" Title="Saving automatically" Subtitle="We save your changes as you go - so you never have to." PreferredPlacement="BottomLeft"> </controls:TeachingTip> </Button.Resources> </Button>

无目标的放置语义

第一个词表示提示居中对齐于 XamlRoot 的哪一侧;有第二个词时提示会靠向对应角落。注意:无目标模式下两个词的顺序不影响结果——TopRightRightTop等价。Center会让提示出现在 XamlRoot 的水平和垂直中心。

源码级回退算法

从 TeachingTip.cpp 的GetPlacementFallbackOrder()可以看到真实的回退优先级:算法维护一个 13 项优先级数组(初始顺序为 Top → Bottom → Left → Right → 四个角 → 四个边 → Center),然后根据首选方向做"交换排序":

  • 首选为 Bottom 系:将 Bottom 提到 Top 之前;
  • 首选为 Left/Right 系:将横向(Left/Right)提到纵向之前,Right 系再把 Right 提到 Left 之前;
  • 最后用std::rotate首选模式旋转到第一位

随后DetermineEffectivePlacementTargeted()对 13 种模式逐一计算可用性(目标是否足够大、是否有足够空间、尖角是否保持 12px 边缘间距等,见原文档"Placement"行为说明),按优先级返回第一个可用模式;若 13 种模式全部不可用,返回tipDoesNotFit = true,此时 TeachingTip 将不会打开,而是迭代完整的事件生命周期强制关闭(并在调试模式下通过TeachingTipTestHooks记录"因无空间而未打开"的遥测计数)。原文档特别警告:如果应用在 Closing 事件中取消了关闭,提示可能保持打开且没有可访问的关闭按钮

非首选因素(placement 不考虑的条件)

根据原文档,以下条件在放置时不会被优先考虑

  • 提示无足够空间完整显示而不被裁剪;
  • 目标不够大,无法维持提示对齐且保持尖角距提示边缘 12px;
  • 目标元素过大,无法在保持尖角居中的同时维持边缘对齐。

放置边距(PlacementMargin)

PlacementMargin控制有目标提示与目标之间、无目标提示与 XamlRoot 边缘之间的间距。与FrameworkElement.Margin相同,它有 Left/Right/Top/Bottom 四个值,只有与当前放置方向相关的值会被使用——例如PlacementMargin.Left仅在提示位于目标左侧或 XamlRoot 左边缘时生效。

<Button x:Name="SaveButton" Content="Save" /> <controls:TeachingTip x:Name="AutoSaveTip" Title="Saving automatically" Subtitle="We save your changes as you go - so you never have to." PreferredPlacement="BottomLeft" PlacementMargin="80"> </controls:TeachingTip>

以上示例将无目标提示的四个方向边距都设为 80。在源码中,PositionPopup()/PositionTargetedPopup()/PositionUntargetedPopup()分别使用这些边距计算最终偏移(UntargetedTipNearPlacementOffsetUntargetedTipFarPlacementOffset等工具函数直接读取s_untargetedTipWindowEdgeMargin与 PlacementMargin 求和)。

内容区、按钮、图标与 Hero Content

添加内容(Content)

任意 XAML 内容都可以放入Content属性:文本、图片、视频、动画、复选框、超链接等。内容超出提示高度时,会自动启用滚动条

<Button x:Name="SaveButton" Content="Save"> <Button.Resources> <controls:TeachingTip x:Name="AutoSaveTip" Target="{x:Bind SaveButton}" Title="Saving automatically" Subtitle="We save your changes as you go - so you never have to."> <StackPanel> <CheckBox x:Name="HideTipsCheckBox" Content="Don't show tips at start up" IsChecked="{x:Bind HidingTips, Mode=TwoWay}" /> <TextBlock>You can change your tip preferences in <Hyperlink NavigateUri="app:/item/SettingsPage">Settings</Hyperlink> if you change your mind.</TextBlock> </StackPanel> </controls:TeachingTip> </Button.Resources> </Button>

添加按钮

默认情况下,标题右侧显示一个标准的X 关闭按钮。可通过CloseButtonContent自定义关闭按钮文案——此时按钮会移动到提示底部。另外可通过ActionButtonContent添加自定义操作按钮,并可选配ActionButtonCommandActionButtonCommandParameter(注意:轻触关闭(light-dismiss)启用的提示不会显示任何关闭按钮)。

<Button x:Name="SaveButton" Content="Save"> <Button.Resources> <controls:TeachingTip x:Name="AutoSaveTip" Target="{x:Bind SaveButton}" Title="Saving automatically" Subtitle="We save your changes as you go - so you never have to." ActionButtonContent="Disable" ActionButtonCommand="DisableAutoSave" CloseButtonContent="Got it!"> <StackPanel> <CheckBox x:Name="HideTipsCheckBox" Content="Don't show tips at start up" IsChecked="{x:Bind HidingTips, Mode=TwoWay}" /> <TextBlock>You can change your tip preferences in <Hyperlink NavigateUri="app:/item/SettingsPage">Settings</Hyperlink> if you change your mind.</TextBlock> </StackPanel> </controls:TeachingTip> </Button.Resources> </Button>

在 TeachingTip.xaml 模板中可以看到ButtonsStates状态组(NoButtonsVisible/ActionButtonVisible/CloseButtonVisible/BothButtonsVisible)与CloseButtonLocations状态组(HeaderCloseButton/FooterCloseButton)共同决定两个按钮的可见性、列位置与间距;AlternateCloseButton则是标题旁的无边框 X 按钮,其样式来自AlternateCloseButtonStyle主题资源。

Hero Content(通栏内容)

通过HeroContent属性添加拉伸到提示边缘的通栏媒体内容(如图片、视频),并用HeroContentPlacement将其置于提示顶部或底部:

<Button x:Name="SaveButton" Content="Save"> <Button.Resources> <controls:TeachingTip x:Name="AutoSaveTip" Target="{x:Bind SaveButton}" Title="Saving automatically" Subtitle="We save your changes as you go - so you never have to."> <controls:TeachingTip.HeroContent> <Image Source="Assets/cloud.png" /> </controls:TeachingTip.HeroContent> </controls:TeachingTip> </Button.Resources> </Button>

模板中的HeroContentPlacementStatesHeroContentTop/HeroContentBottom)通过HeroContentBorder的 Grid.Row 与圆角转换器实现上下切换。值得注意的细节(源码UpdateDynamicHeroContentPlacementToTop/Bottom与行为表"Tail/Hero Content Avoidance"):为避免尖角从 Hero Content 中"长出"的视觉怪相,控件会依次尝试:将 Hero 内容移到顶部或底部(HeroContentPlacement非 Auto 时禁用)、沿提示边缘平移尖角(edge-aligned 放置时禁用)、更换提示放置模式(非 Auto 放置时禁用)。

添加图标(IconSource)

使用IconSource在标题/副标题旁添加图标,推荐尺寸为 16px、24px、32px:

<Button x:Name="SaveButton" Content="Save"> <Button.Resources> <controls:TeachingTip x:Name="AutoSaveTip" Target="{x:Bind SaveButton}" Title="Saving automatically" Subtitle="We save your changes as you go - so you never have to."> <controls:TeachingTip.IconSource> <controls:SymbolIconSource Symbol="Save" /> </controls:TeachingTip.IconSource> </controls:TeachingTip> </Button.Resources> </Button>

模板中IconPresenter通过绑定TemplateSettings.IconElement渲染图标(IconStates状态组控制有无图标时的间距),TeachingTipTemplateSettings类(见 TeachingTip.idl)还暴露TopRightHighlightMargin/TopLeftHighlightMargin两个 Thickness,用于让容器顶部 1px 高光边缘"避让"尖角,保持视觉连续。

轻触关闭(Light-dismiss)

IsLightDismissEnabled默认关闭。开启后,提示会在用户滚动或与应用其他元素交互时自动消失,因此当提示需要放置在可滚动区域中时,轻触关闭是最佳方案。开启后控件会自动移除关闭按钮,以向用户表明其轻触关闭行为(模板LightDismissStates状态组同时会把背景切换为TeachingTipTransientBackground半透明画刷)。

<Button x:Name="SaveButton" Content="Save" /> <controls:TeachingTip x:Name="AutoSaveTip" Title="Saving automatically" Subtitle="We save your changes as you go - so you never have to." IsLightDismissEnabled="True"> </controls:TeachingTip>

源码层面,CreateLightDismissIndicatorPopup()会创建专门的m_lightDismissIndicatorPopup用于捕获提示之外的点击/滚动;OnLightDismissIndicatorPopupClosed()回调负责按LightDismiss原因触发关闭流程。IDL 中TeachingTipCloseReason枚举的三个成员(CloseButton/LightDismiss/Programmatic)正是Closing/Closed事件参数Reason的取值来源。

逃逸 XamlRoot 边界(ShouldConstrainToRootBounds)

Windows 19H1 及以上版本,设置ShouldConstrainToRootBounds="False"可以让提示逃逸 XamlRoot 与屏幕边界,始终按设定的PreferredPlacement定位。官方强烈建议同时启用IsLightDismissEnabled,并将PreferredPlacement设为最接近 XamlRoot 中心的模式,以保证最佳体验。在更早的 Windows 版本上该属性会被忽略,提示始终约束在 XamlRoot 内。

<Button x:Name="SaveButton" Content="Save" /> <controls:TeachingTip x:Name="AutoSaveTip" Title="Saving automatically" Subtitle="We save your changes as you go - so you never have to." PreferredPlacement="BottomRight" PlacementMargin="-80,-50,0,0" ShouldConstrainToRootBounds="False"> </controls:TeachingTip>

从 TeachingTip.cpp 的DetermineEffectivePlacement()可以看到:当ShouldConstrainToRootBounds()为 false 时,放置算法切换到GetEffectiveScreenBoundsInCoreWindowSpace()得到的屏幕边界而非窗口边界(源码注释也指出:由于缺少多显示器 API 信息,超出根边界的场景不做特殊计算,默认返回首选值或 Top,该行为可通过SetReturnTopForOutOfWindowPlacement测试钩子调整)。

取消与延迟关闭(Closing / Closed 事件)

Closing事件可用于**取消(cancel)或延迟(defer)**提示的关闭,以便保持提示打开、为某个动作或自定义动画争取时间。关键行为:

  • 关闭被取消时,IsOpen回到 true
  • 延迟期间(deferral 未完成时)IsOpen保持 false;
  • 程序化关闭同样可以被取消
<controls:TeachingTip x:Name="EnableNewSettingsTip" Title="New ways to protect your privacy!" Subtitle="Please close this tip and review our updated privacy policy and privacy settings." Closing="OnTipClosing"> </controls:TeachingTip>
public async void OnTipClosing(object sender, TeachingTipClosingEventArgs args) { if (args.Reason == TeachingTipCloseReason.CloseButton) { using (args.GetDeferral()) { bool success = await UpdateUserSettings(User thisUsersID); if (!success) { // We were not able to update the settings! // Don't close the tip and display the reason why. args.Cancel = true; ShowLastErrorMessage(); } } } }

重要警告(原文档原文强调):如果没有任何放置选项能让提示完整显示,提示会迭代完整的事件生命周期以强制关闭,而不是在缺少可访问关闭按钮的情况下显示。如果应用此时取消了Closing事件,提示可能保持打开且没有可访问的关闭按钮。

IDL 中TeachingTipClosingEventArgs暴露Reason(只读)、Cancel(可写)与GetDeferral()TeachingTipClosedEventArgs只暴露Reason。另外仓库源码中还有一个[MUX_PREVIEW]Opened事件(TeachingTipOpenedEventArgs),用于打开完成的回调。

重新配置已打开的提示(Reconfiguring)

部分内容与属性可以在提示打开期间修改并立即生效;但以下变更必须关闭并重新打开才会生效:

  • 图标属性(IconSource);
  • Action / Close 按钮相关属性;
  • 在轻触关闭与显式关闭之间切换。

特别注意(原文档警告):在提示打开时从手动关闭(manual-dismiss)切换到轻触关闭,会先移除关闭按钮再启用轻触关闭行为,提示可能卡在屏幕上无法关闭

事件与 API 速查

Notable Properties(API Notes 原表)

属性说明
TailVisibility获取或设置提示尖角是折叠还是保持可见(Auto / Visible / Collapsed)
PreferredPlacement获取或设置提示的默认放置模式
ShouldConstrainToRootBounds获取或设置提示是否约束在根边界内

Events(原表)

事件说明
ActionButtonClick操作按钮被点击后发生
CloseButtonClick关闭按钮被点击后发生
Closed提示关闭后发生
Closing提示即将开始关闭时发生

完整属性清单(来自 IDL,含默认值)

属性类型 / 默认值
Title / Subtitlestring
IsOpenbool,默认false
TargetFrameworkElement
TailVisibility默认Auto
ActionButtonContent / ActionButtonStyle / ActionButtonCommand / ActionButtonCommandParameterobject / Style / ICommand / object
CloseButtonContent / CloseButtonStyle / CloseButtonCommand / CloseButtonCommandParameterobject / Style / ICommand / object
PlacementMarginThickness
ShouldConstrainToRootBoundsbool,默认true
IsLightDismissEnabledbool,默认false
PreferredPlacement默认Auto
HeroContentPlacement默认Auto
HeroContent / IconSourceUIElement / IconSource
TemplateSettingsTeachingTipTemplateSettings(只读)

视觉与行为组件详解(原文档 Appendix)

视觉组件(Visual Components)

组件说明
Container提示主体,封装所有组件;非模态;内容高度/宽度超过上限时启用垂直滚动;外缘有随尖角贴合的过程描边;顶部边缘有 1px 高光并随尖角贴合
Title半粗体,在关闭按钮与容器边框处自动换行
Subtitle在关闭按钮与容器边框处自动换行
Content可定制任意 XAML 内容;超过高度时滚动;位于 Subtitle 下方、关闭/操作按钮上方
Close Button默认在右上角显示 X(RTL 语言自动移到左上角);可设置为底部常规按钮,也可完全隐藏以便在内容区自定义关闭方式;轻触关闭时完全不显示
Action Button允许用户触发自定义事件;这是开箱提供的唯一非关闭按钮
Tail指向屏幕 UI 元素的三角形延伸;TailVisibility为 Auto 时,有目标自动显示、无目标自动隐藏;优先居中于目标;距提示边缘保持12px间距;不参与动画;无阴影(非矩形表面暂不支持阴影)
Icon默认位于标题/副标题左侧,RTL 时自动移到右侧
Hero Content拉伸到提示边缘的媒体;可置于顶部或底部
Scroll Bar内容过大时出现在内容区,不会与右上角 X 按钮相交

关于 Tail 的形状细节,源码注释(TeachingTip.h)特别说明:尖角设计为 8x16 像素形状,实际实现为 10x20 形状并部分被提示内容遮挡,这样可以让提示边框沿尖角形状贴合,而无需在尖角与提示主体相接的边上画边框。同时MinimumTipEdgeToTailEdgeMargin()等函数精确计算了尖角与边缘的最小间距。

行为组件(Behavioral Components)

行为说明
Opening通过IsOpen = true显示,带开启动画;若任何位置都无足够空间完整显示,则不会打开并将 IsOpen 覆写为 false
Closing三种关闭方式:程序设IsOpen=false、用户点击关闭按钮、轻触关闭;用TeachingTipCloseReason区分;可用Cancel=true阻止关闭;可用 deferral 异步响应
Placement有目标放置遵循 Flyout 先例,Center使尖角指向元素中心;无目标放置覆盖窗口每侧、每角与中心;不优先考虑:无足够空间、目标过小、目标过大无法保持尖角居中
Light-dismiss用户滚动或点击应用其他区域时关闭
Persistent Tip Location打开后提示不会随目标移动(窗口调整大小除外)
Motion内置开/关动画,可通过 Storyboard 自定义(源码中CreateExpandAnimation/CreateContractAnimation,默认展开 300ms、收起 200ms,均可用测试钩子调整)
Tail/Hero Content Avoidance依次尝试移动 Hero 内容、平移尖角、更换放置模式,避免尖角与 Hero 内容相交
Out of Window Bounds新系统上可用ShouldConstrainToRootBounds=false让提示逃逸窗口,改用屏幕边界参与放置算法

输入与无障碍(Inputs & Accessibility)

UI Automation 模式

  • TeachingTip 会在持久提示轻触关闭提示之间切换 Pane / Window 自动化模式;
  • 可滚动内容区提供IScrollProvider
  • 实现自定义的"tip" Landmark(模板中ContentRootGrid设置了AutomationProperties.LandmarkType="Custom",与规范一致)。

键盘导航

状态操作
提示出现无需任何操作即可调用提示
提示获得焦点F6:提示被加入 F6 区域导航停止点,可用 F6 进入/离开;Tab:Narrator 激活时,提示自动加入 Narrator 导航停止点顶部(类似 Popup / ContentDialog),可通过 Tab 进入
Tab 遍历提示Tab:按顺序遍历所有可操作项;在最后一个元素上按 Tab,焦点循环回第一个元素;左右方向键:两个底部按钮都存在时可在其间导航;Esc:关闭提示
提示被关闭1. 按 X 按钮;2. 按关闭按钮;3. 按操作按钮。Tab 使焦点前进到下一元素但不会关闭提示

Narrator

TeachingTip 复用 Windows 通知使用的现有 API。有目标提示会注入其目标名称,在标题前与标题一起被 Narrator 朗读,提供目标上下文。通知语音流程:"Click Up to move to new notification from" + App 名 + 提示内容;触摸屏设备上可通过Swipe遍历所有可操作项,在最后一项再次滑动会将焦点移到 Narrator 的全屏隐形关闭按钮,双击屏幕关闭窗口,再次滑动移出提示。

游戏手柄(Gamepad)

状态操作
提示出现无需操作
提示获得焦点空间导航(spatial navigation)可访问提示;官方建议为提示可达性与测试做合理设计
提示被导航空间导航遍历可操作项;A 键交互(如"按下"操作/关闭按钮);B 键关闭提示
提示被关闭1. 头部 X 按钮;2. 底部关闭按钮;3. 操作按钮;4. B 键将焦点还给之前聚焦的元素

原文档明确提醒:TeachingTip 的手柄可达性并不被保证,因此针对预测手柄输入的应用,必须用应用 UI 的所有可能配置逐一测试。

结语:一段可复制的完整示例

结合以上所有特性,下面是一个同时包含目标、内容、Hero 内容、图标、双按钮与延迟关闭检查的完整示例,可直接在 WinUI 3 应用中运行:

<Button x:Name="SaveButton" Content="Save"> <Button.Resources> <controls:TeachingTip x:Name="AutoSaveTip" Target="{x:Bind SaveButton}" Title="Saving automatically" Subtitle="We save your changes as you go - so you never have to." PreferredPlacement="Bottom" PlacementMargin="12" ActionButtonContent="Disable" CloseButtonContent="Got it!" Closing="OnTipClosing"> <controls:TeachingTip.IconSource> <controls:SymbolIconSource Symbol="Save" /> </controls:TeachingTip.IconSource> <controls:TeachingTip.HeroContent> <Image Source="Assets/cloud.png" /> </controls:TeachingTip.HeroContent> <StackPanel> <CheckBox Content="Don't show tips at start up" /> </StackPanel> </controls:TeachingTip> </Button.Resources> </Button>
private void OnTipClosing(TeachingTip sender, TeachingTipClosingEventArgs args) { if (args.Reason == TeachingTipCloseReason.CloseButton) { // 在此执行必要的清理,若失败则 args.Cancel = true 阻止关闭 } }

后续你可以:

  • 阅读 控件源码 深入放置算法、动画与焦点处理;
  • 查看 API 测试 与 交互测试 了解已验证的行为矩阵;
  • 在 TestUI 页面 中探索控件在真实应用里的各种配置形态;
  • 参考 视觉组件附录图片(Container、Title、ScrollBar 等)核对控件外观规格。

【免费下载链接】microsoft-ui-xamlWinUI: a modern UI framework with a rich set of controls and styles to build dynamic and high-performing Windows applications.项目地址: https://gitcode.com/GitHub_Trending/mi/microsoft-ui-xaml

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 14:05:20

Hydra配置管理:Python机器学习实验的可复现治理方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 14:01:33

Linux vi编辑器实战入门:模式切换与终端编辑核心技能

简介&#xff1a;本资源是一份面向Linux初学者与计算机专业学生的Vi编辑器实践教学材料&#xff0c;聚焦命令行文本编辑核心技能训练&#xff0c;解决新手在系统配置、代码编写及日常文件处理中因不熟悉Vi操作而效率低下的问题。资源为单文件PDF文档&#xff08;422KB&#xff…

作者头像 李华
网站建设 2026/9/17 14:01:31

SSM动漫之家论坛系统实战:数据建模、分页查询与事务管理

简介&#xff1a;面向Java Web课程设计、毕业设计与SSM框架入门者的《基于Java动漫之家系统设计与实现》文档&#xff0c;围绕动漫资讯平台这一典型场景&#xff0c;完整呈现从选题背景、技术选型到功能实现与测试的成体系方案。内容以SSM&#xff08;Spring、SpringMVC、MyBat…

作者头像 李华
网站建设 2026/9/17 13:59:44

从PDF到LaTeX:数学公式提取与知识库构建实战

简介&#xff1a;这是一份面向考研学子的数学公式速查手册&#xff0c;专为应对研究生入学考试中的高等数学、线性代数、概率论等科目而整理&#xff0c;帮助考生解决公式繁多、易混淆、不会运用等痛点。资源包内为一份PDF电子文档&#xff0c;压缩包整体大小约3.16MB&#xff…

作者头像 李华
网站建设 2026/9/17 13:59:15

Ubuntu下无root导出微信聊天记录:SQLCipher解密与CSV分析

1. 这不是“破解”&#xff0c;而是一场标准的数据主权实践你有没有过这样的时刻&#xff1a;换新手机前夜&#xff0c;盯着微信里几千条聊天记录发呆——那些和家人确认年夜饭菜单的语音、和同事敲定项目节点的文字、甚至自己随手发的备忘录图片&#xff0c;全被锁在一台设备里…

作者头像 李华