閱讀導航
前言
案例一
案例二
案例三(本文介紹的方式)
如何使用?
控件如何開發的?
總結
1. 前言
案例一
站長分享過 眾尋 大佬的一篇 WPF 簡易新手引導 一文,新手引導的效果挺不錯的,如下圖:

該文給出的代碼未使用 MVVM 的開發方式,提示框使用的用戶控件、蒙版窗體樣式與后臺代碼未分離,但給大家分享了開發新手引導功能的一個參考。
案例二
開源項目 AIStudio.Wpf.Controls,它的新手引導效果如下:
此開源項目也有參考上文(WPF 簡易新手引導),并且重構為 MVVM 版本,方便綁定使用。
并且提示框顯示的位置還跟隨目標控件在主窗體中的位置靈活變換,不至于顯示在蒙版窗體之外,如下圖所示:
當目標控件右側空間足夠顯示引導提示框時,引導提示框就顯示在目標控件右側;在右側空間不足時,則將引導提示框顯示在目標控件左側:
案例三(本文介紹的方式)
站長根據上面的開源項目 AIStudio.Wpf.Controls 做了一個自己的版本 Dotnet9WPFControls,去掉了上一步按鈕、增加標題綁定、下一步按鈕內容綁定、提示框樣式修改等,效果如下:

后面段落就介紹 怎么使用 Dotnet9WPFControls 添加新手引導功能,并簡單提及這個自定義控件的開發細節,主要原理還是看上文 WPF 簡易新手引導 哈。
希望對有需要給自己的項目添加新手引導功能的朋友有一定幫助,通過此文你也能修改出滿足自己需求的效果。
2. 如何使用?
2.1 創建一個WPF項目
使用 .NET 6|7 創建一個名為 "NewbieGuideDemo" 的 WPF 解決方案:

2.2 引入nuget包
添加Nuget包1:Dotnet9WPFControls
該包提供引導控件及其樣式,記得勾選“包括預發行版”,然后點擊安裝。

添加Nuget包2:Prism.DryIoc
使用該包,主要是使用 Prism 封裝的一些 MVVM、IOC 功能,方便協助開發。
添加上述兩個Nuget包后,項目工程文件定義如下:
<Project?Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>WinExe</OutputType><TargetFramework>net6.0-windows</TargetFramework><Nullable>enable</Nullable><UseWPF>true</UseWPF></PropertyGroup><ItemGroup><PackageReference?Include="Dotnet9WPFControls"?Version="0.1.0-preview.2"?/><PackageReference?Include="Prism.DryIoc"?Version="8.1.97"?/></ItemGroup></Project>
2.3 添加樣式文件
打開 App.xaml
文件,引入 Dotnet9WPFControls 默認主題文件:
<prism:PrismApplicationx:Class="NewbieGuideDemo.App"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:prism="http://prismlibrary.com/"><prism:PrismApplication.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><ResourceDictionary?Source="pack://application:,,,/Dotnet9WPFControls;component/Themes/Dotnet9WPFControls.xaml"?/></ResourceDictionary.MergedDictionaries></ResourceDictionary></prism:PrismApplication.Resources>
</prism:PrismApplication>
注意上面的根節點 <prism:PrismApplication />
,同時修改App.xaml.cs
文件,這里不做過多說明,具體使用請參考 Prism:
using?Prism.DryIoc;
using?Prism.Ioc;
using?System.Windows;namespace?NewbieGuideDemo
{public?partial?class?App?:?PrismApplication{protected?override?void?RegisterTypes(IContainerRegistry?containerRegistry){}protected?override?Window?CreateShell(){return?Container.Resolve<MainWindow>();}}
}
2.4 定義引導信息
給主窗體 MainWindow
添加一個 ViewModel 類:MainWindowViewModel.cs
:
using?Dotnet9WPFControls.Controls;
using?Prism.Mvvm;
using?System.Collections.Generic;namespace?NewbieGuideDemo
{public?class?MainWindowViewModel?:?BindableBase{private?GuideInfo??_guide;public?GuideInfo?Guide?=>_guide???=?new?GuideInfo("快速添加新手引導",?"這樣添加新手引導,或許比較優雅");public?List<GuideInfo>?Guides?=>?new()?{Guide};}
}
在上面的 ViewModel 中,定義了一個引導屬性 Guide
,這個屬性是與提示框綁定展示:

第一個參數定義了引導提示框的標題
“快速添加新手引導”
第二個參數定義了引導提示框的提示內容
“這樣添加新手引導,或許比較優雅”
第二個屬性 Guides
, 是一個引導信息列表,可綁定多個引導信息,點擊按鈕即會查看下一個引導,本示例為了演示,只寫了一個引導。
2.5 界面綁定引導信息
先貼上 MainWindow.xaml
所有代碼:
<Windowx:Class="NewbieGuideDemo.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:prism="http://prismlibrary.com/"xmlns:i="http://schemas.microsoft.com/xaml/behaviors"xmlns:dotnet9="https://dotnet9.com"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"Title="Dotnet9?WPF新手引導功能"?Width="800"?Height="450"prism:ViewModelLocator.AutoWireViewModel="True"AllowsTransparency="True"?Background="Transparent"?WindowStyle="None"?WindowStartupLocation="CenterScreen"mc:Ignorable="d"><Window.Resources><dotnet9:BindControlToGuideConverter?x:Key="BindControlToGuideConverter"?/></Window.Resources><BorderBackground="White"?BorderBrush="#ccc"?BorderThickness="1"?MouseLeftButtonDown="Border_MouseDown"><Grid><Button?HorizontalAlignment="Center"?VerticalAlignment="Center"?Content="點擊測試新手引導"><dotnet9:GuideHelper.GuideInfo><MultiBinding?Converter="{StaticResource?BindControlToGuideConverter}"><Binding?RelativeSource="{RelativeSource?Self}"?/><Binding?Path="Guide"?/></MultiBinding></dotnet9:GuideHelper.GuideInfo><i:Interaction.Triggers><i:EventTrigger?EventName="Click"><i:ChangePropertyAction?PropertyName="Display"?TargetName="GuideControl"?Value="True"?/></i:EventTrigger></i:Interaction.Triggers></Button><dotnet9:GuideControl?x:Name="GuideControl"?Guides="{Binding?Guides}"><i:Interaction.Triggers><i:EventTrigger?EventName="Loaded"><i:ChangePropertyAction?PropertyName="Display"?Value="True"?/></i:EventTrigger></i:Interaction.Triggers></dotnet9:GuideControl></Grid></Border>
</Window>
下面快速過一遍。
2.5.1 引入的命名空間說明
看上面的代碼,引入了 dotnet9
和 prism
、i
三個命名空間:
dotnet9
命名空間
引入引導控件 GuideControl
及 轉換器 BindControlToGuideConverter
。
prism
命名空間
主要用途在 prism:ViewModelLocator.AutoWireViewModel="True"
這句代碼,將視圖 MainWindow.xaml
與 MainWindowViewModel.cs
進行綁定,有興趣可以看 Prism 源碼,了解視圖是如何發現ViewModel的約定規則。
i
命名空間
主要用此命名空間下的觸發器,事件觸發屬性更改。
2.5.2 幾處關鍵代碼簡單說明
上面代碼貼的是引導控件(自定義控件)的使用方式(站長注:Dotnet9WPFControls 中還有引導窗體的方式,本文不做說明,要不然太占篇幅了,請查看控件Demo GuideWindowView)。
a: 將引導控件加到容器最上層
先關注后面的幾行代碼:
<Grid><!--這里省略業務控件布局--><dotnet9:GuideControl?x:Name="GuideControl"?Guides="{Binding?Guides}"><i:Interaction.Triggers><i:EventTrigger?EventName="Loaded"><i:ChangePropertyAction?PropertyName="Display"?Value="True"?/></i:EventTrigger></i:Interaction.Triggers></dotnet9:GuideControl>
</Grid>
將引導控件加到
Grid
容器最后,意圖是讓引導控件顯示在所有控件的最上層(同一層級添加了多個控件,如果位置重疊,那么后加入的控件會顯示在先添加的控件上方,呈現遮擋效果);綁定了前面
MainWindowViewModel
中定義的引導信息列表Guides
,點擊下一步按鈕(本文顯示為我知道了
)時,會按列表添加順序切換引導信息;使用
i:Interaction.Triggers
實現控件加載完成時,自動顯示引導提示信息,見上面的 示例三效果;
b:綁定目標控件與引導屬性
目標控件的引導屬性與目標控件引用綁定
,引導界面顯示時通過目標控件計算出目標控件的位置和大小,準確將目標控件標識出來,引導提示框定位也才能正確設置:
<dotnet9:BindControlToGuideConverter?x:Key="BindControlToGuideConverter"?/>
<Button?HorizontalAlignment="Center"?VerticalAlignment="Center"?Content="點擊測試新手引導"><dotnet9:GuideHelper.GuideInfo><MultiBinding?Converter="{StaticResource?BindControlToGuideConverter}"><Binding?RelativeSource="{RelativeSource?Self}"?/><Binding?Path="Guide"?/></MultiBinding></dotnet9:GuideHelper.GuideInfo><i:Interaction.Triggers><i:EventTrigger?EventName="Click"><i:ChangePropertyAction?PropertyName="Display"?TargetName="GuideControl"?Value="True"?/></i:EventTrigger></i:Interaction.Triggers>
</Button>
如上代碼引入 BindControlToGuideConverter 轉換器
, 該轉換器是個黏合類,將目標控件的引用添加到引導對象上,轉換器具體定義如下:
public?class?BindControlToGuideConverter?:?IMultiValueConverter
{public?object??Convert(object[]?values,?Type?targetType,?object?parameter,?CultureInfo?culture){if?(values.Length?<?2){return?null;}var?element?=?values[0]?as?FrameworkElement;var?guide?=?values[1]?as?GuideInfo;if?(guide?!=?null){guide.TargetControl?=?element;}return?guide;}public?object[]?ConvertBack(object?value,?Type[]?targetTypes,?object?parameter,?CultureInfo?culture){throw?new?NotImplementedException();}
}
目標控件的引用賦值給引導對象的 TargetControl
屬性。
Demo代碼完畢,直接運行項目,效果如下,源碼在這 NewbieGuideDemo:

3. 控件如何開發的?
關于原理,WPF 簡易新手引導 這篇介紹的不錯,可以先看看。
關于本示例的實現方式,暫時不做太多說明,詳細請直接查看源碼 Dotnet9WPFControls,本文后半截大概提一下。
代碼組織結構如下:

GuideInfo:定義引導信息類,如標題、內容、下一步按鈕顯示內容。
GuideHintControl:引導提示框控件,顯示引導標題、引導內容、下一步按鈕,即
GuideInfo
綁定的控件。GuideControl:引導控件,用于目標控件無法獲取到自己的窗體這種(即無法獲取在窗體中的位置),比如您開發的程序為第三方程序插件這種,上面的代碼即是使用此引導控件實現的效果。
GuideWindow:引導窗體,
GuideControl
引導控件的相互補充。GuideControlBase:引導控件輔助類
BindControlToGuideConverter:引導信息與引導的目標控件綁定轉換器
GuideHelper:引導幫助類,綁定目標控件的引導信息使用,外加一個顯示 引導窗體 的靜態命令。
Guide.xaml:定義引導遮罩層(
GuideControl
和GuideWindow
)、引導提示框(GuideHintControl
)樣式的資源文件,定義外觀請改這個文件
重點:
a)
GuideControlBase
GuideControlBase
是 GuideControl
和 GuideWindow
的輔助類,因為這兩個類實現的功能是類似的,所以封裝大部分功能在 GuideControlBase
中,比如將目標控件區域從遮罩層 Clip 出來,并將 GuideHintControl
提示框控件添加到遮罩層之上,顯示出新手引導的效果。
b)
GuideControl 和 GuideWindow
GuideControl
是用于顯示在包含目標控件的容器內使用的,GuideControl
放置的容器不一定是目標控件的直接容器,可以有嵌套,比如目標控件在ListBox
子項ListBoxItem
內,而引導控件GuideControl
可以在ListBox
的外層容器之上;
GuideWindow
用于貼在目標控件所在的窗體上,GuideWindow
作為目標控件窗體的子窗體,Show()
在目標控件窗體上,不能使用ShowDialog()
的方式(為啥?ShowDialog()
會使除引導窗體之外的窗體處于無效狀態(disable))。
這兩種方式(GuideControl 和 GuideWindow)總體呈現效果是一樣的,目標控件所在的窗體是自定義窗體,Demo能正常顯示下面的效果,普通窗體需要對目標控件 Clip 的位置和提示框的位置進行偏移處理,修改位置見 GuideControl
和 GuideWindow
的方法 ShowGuide(FrameworkElement? targetControl, GuideInfo guide)
。
控件帶的兩個新手引導Demo如下:
新手引導Demo一
GuideControl方式,站長推薦,即以控件的方式顯示新手引導,點擊看代碼:

新手引導Demo二
GuideWindow方式,即以子窗體的方式顯示新手引導,點擊看代碼:
詳細開發不展開說了,一切都在代碼中。
4. 總結
前面寫了不少,其實不多,謝謝開源帶來的力量。
參考文章:WPF 簡易新手引導
參考開源項目:AIStudio.Wpf.Controls
本文Demo
NewbieGuideDemo
:Github、GiteeDotnet9Controls 新手引導Demo一 源碼:Github、Gitee
Dotnet9Controls 新手引導Demo二 源碼
GuideWindowView
:Github、GiteeDotnet9Controls控件:Github、Gitee