WPF|快速添加新手引導(dǎo)功能(支持MVVM)
閱讀導(dǎo)航
前言
案例一
案例二
案例三(本文介紹的方式)
如何使用?
控件如何開發(fā)的?
總結(jié)
1. 前言
案例一
站長分享過?眾尋?大佬的一篇?WPF 簡易新手引導(dǎo)?一文,新手引導(dǎo)的效果挺不錯的,如下圖:

該文給出的代碼未使用?MVVM?的開發(fā)方式,提示框使用的用戶控件、蒙版窗體樣式與后臺代碼未分離,但給大家分享了開發(fā)新手引導(dǎo)功能的一個參考。
案例二
開源項目?AIStudio.Wpf.Controls,它的新手引導(dǎo)效果如下:

此開源項目也有參考上文(WPF 簡易新手引導(dǎo)),并且重構(gòu)為?MVVM?版本,方便綁定使用。
并且提示框顯示的位置還跟隨目標(biāo)控件在主窗體中的位置靈活變換,不至于顯示在蒙版窗體之外,如下圖所示:
當(dāng)目標(biāo)控件右側(cè)空間足夠顯示引導(dǎo)提示框時,引導(dǎo)提示框就顯示在目標(biāo)控件右側(cè);在右側(cè)空間不足時,則將引導(dǎo)提示框顯示在目標(biāo)控件左側(cè):

案例三(本文介紹的方式)
站長根據(jù)上面的開源項目?AIStudio.Wpf.Controls?做了一個自己的版本?Dotnet9WPFControls,去掉了上一步按鈕、增加標(biāo)題綁定、下一步按鈕內(nèi)容綁定、提示框樣式修改等,效果如下:

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

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

添加Nuget包2:Prism.DryIoc
使用該包,主要是使用?Prism?封裝的一些?MVVM、IOC?功能,方便協(xié)助開發(fā)。
添加上述兩個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 添加樣式文件
打開??文件,引入?Dotnet9WPFControls?默認(rèn)主題文件:
<prism:Prismapplication ? ?x: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>
注意上面的根節(jié)點?,同時修改
文件,這里不做過多說明,具體使用請參考?Prism:
2.4 定義引導(dǎo)信息
給主窗體??添加一個 ViewModel 類:
:
在上面的 ViewModel 中,定義了一個引導(dǎo)屬性?,這個屬性是與提示框綁定展示:

第一個參數(shù)定義了引導(dǎo)提示框的標(biāo)題?
第二個參數(shù)定義了引導(dǎo)提示框的提示內(nèi)容?
第二個屬性?, 是一個引導(dǎo)信息列表,可綁定多個引導(dǎo)信息,點擊按鈕即會查看下一個引導(dǎo),本示例為了演示,只寫了一個引導(dǎo)。
2.5 界面綁定引導(dǎo)信息
先貼上??所有代碼:
<Window ? ?x: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新手引導(dǎo)功能" 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> ? ?<Border ? ? ? ?Background="White" BorderBrush="#ccc" BorderThickness="1" MouseLeftButtonDown="Border_MouseDown"> ? ? ? ?<Grid> ? ? ? ? ? ?<Button HorizontalAlignment="Center" VerticalAlignment="Center" Content="點擊測試新手引導(dǎo)"> ? ? ? ? ? ? ? ?<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 引入的命名空間說明
看上面的代碼,引入了??和?
、
三個命名空間:
?命名空間
引入引導(dǎo)控件??及 轉(zhuǎn)換器?
。
?命名空間
主要用途在??這句代碼,將視圖?
?與?
進行綁定,有興趣可以看?Prism?源碼,了解視圖是如何發(fā)現(xiàn)ViewModel的約定規(guī)則。
?命名空間
主要用此命名空間下的觸發(fā)器,事件觸發(fā)屬性更改。
2.5.2 幾處關(guān)鍵代碼簡單說明
上面代碼貼的是引導(dǎo)控件(自定義控件)的使用方式(站長注:Dotnet9WPFControls?中還有引導(dǎo)窗體的方式,本文不做說明,要不然太占篇幅了,請查看控件Demo?GuideWindowView)。
a: 將引導(dǎo)控件加到容器最上層
先關(guān)注后面的幾行代碼:
<Grid> ? ?<!--這里省略業(yè)務(wù)控件布局--> ? ?<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>
將引導(dǎo)控件加到?
?容器最后,意圖是讓引導(dǎo)控件顯示在所有控件的最上層(同一層級添加了多個控件,如果位置重疊,那么后加入的控件會顯示在先添加的控件上方,呈現(xiàn)遮擋效果);
綁定了前面?
?中定義的引導(dǎo)信息列表?
,點擊下一步按鈕(本文顯示為
)時,會按列表添加順序切換引導(dǎo)信息;
使用?
實現(xiàn)控件加載完成時,自動顯示引導(dǎo)提示信息,見上面的 示例三效果;
b:綁定目標(biāo)控件與引導(dǎo)屬性
,引導(dǎo)界面顯示時通過目標(biāo)控件計算出目標(biāo)控件的位置和大小,準(zhǔn)確將目標(biāo)控件標(biāo)識出來,引導(dǎo)提示框定位也才能正確設(shè)置:
<dotnet9:BindControlToGuideConverter x:Key="BindControlToGuideConverter" /><Button HorizontalAlignment="Center" VerticalAlignment="Center" Content="點擊測試新手引導(dǎo)"> ? ?<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>
如上代碼引入?, 該轉(zhuǎn)換器是個黏合類,將目標(biāo)控件的引用添加到引導(dǎo)對象上,轉(zhuǎn)換器具體定義如下:
目標(biāo)控件的引用賦值給引導(dǎo)對象的??屬性。
Demo代碼完畢,直接運行項目,效果如下,源碼在這?NewbieGuideDemo:

3. 控件如何開發(fā)的?
關(guān)于原理,WPF 簡易新手引導(dǎo)?這篇介紹的不錯,可以先看看。
關(guān)于本示例的實現(xiàn)方式,暫時不做太多說明,詳細(xì)請直接查看源碼?Dotnet9WPFControls,本文后半截大概提一下。
代碼組織結(jié)構(gòu)如下:

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

新手引導(dǎo)Demo二
GuideWindow方式,即以子窗體的方式顯示新手引導(dǎo),點擊看代碼:

詳細(xì)開發(fā)不展開說了,一切都在代碼中。
4. 總結(jié)
前面寫了不少,其實不多,謝謝開源帶來的力量。
參考文章:WPF 簡易新手引導(dǎo)
參考開源項目:AIStudio.Wpf.Controls
本文Demo?
:Github、Gitee
Dotnet9Controls 新手引導(dǎo)Demo一 源碼:Github、Gitee
Dotnet9Controls 新手引導(dǎo)Demo二 源碼?
:Github、Gitee
Dotnet9Controls控件:Github、Gitee