WPF|快速添加新手引导功能(支持MVVM)

阅读导航

  1. 前言

  • 案例一

  • 案例二

  • 案例三(本文介绍的方式)

  1. 如何使用?

  2. 控件如何开发的?

  3. 总结

1. 前言

案例一

站长分享过 眾尋 大佬的一篇 WPF 简易新手引导 一文,新手引导的效果挺不错的,如下图:

7f2bf0c7fad2882be9b6c22ec04fd226.gif

该文给出的代码未使用 MVVM 的开发方式,提示框使用的用户控件、蒙版窗体样式与后台代码未分离,但给大家分享了开发新手引导功能的一个参考。

案例二

开源项目 AIStudio.Wpf.Controls,它的新手引导效果如下:

346c8ecbe821798660bc5c3fb8879ca5.gif

此开源项目也有参考上文(WPF 简易新手引导),并且重构为 MVVM 版本,方便绑定使用。

并且提示框显示的位置还跟随目标控件在主窗体中的位置灵活变换,不至于显示在蒙版窗体之外,如下图所示:

当目标控件右侧空间足够显示引导提示框时,引导提示框就显示在目标控件右侧;在右侧空间不足时,则将引导提示框显示在目标控件左侧:

124a795810468a2cd86c5f9bf17d270d.png

案例三(本文介绍的方式)

站长根据上面的开源项目 AIStudio.Wpf.Controls 做了一个自己的版本 Dotnet9WPFControls,去掉了上一步按钮、增加标题绑定、下一步按钮内容绑定、提示框样式修改等,效果如下:

42861cc355c6c870922a371b5945ac18.gif

后面段落就介绍 怎么使用 Dotnet9WPFControls 添加新手引导功能,并简单提及这个自定义控件的开发细节,主要原理还是看上文 WPF 简易新手引导 哈。

希望对有需要给自己的项目添加新手引导功能的朋友有一定帮助,通过此文你也能修改出满足自己需求的效果。

2. 如何使用?

2.1 创建一个WPF项目

使用 .NET 6|7 创建一个名为 "NewbieGuideDemo" 的 WPF 解决方案:

37afba082f9951a9b05eefafb478b826.png

2.2 引入nuget包

  • 添加Nuget包1:Dotnet9WPFControls

该包提供引导控件及其样式,记得勾选“包括预发行版”,然后点击安装。

6c8db172262fc2b170ffd32ceb7ae6ae.png
  • 添加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,这个属性是与提示框绑定展示:

50903a187cb12829d6d6ef996558d58a.png
  • 第一个参数定义了引导提示框的标题 “快速添加新手引导”

  • 第二个参数定义了引导提示框的提示内容 “这样添加新手引导,或许比较优雅”

第二个属性 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 引入的命名空间说明

看上面的代码,引入了 dotnet9prismi三个命名空间:

  • dotnet9 命名空间

引入引导控件 GuideControl 及 转换器 BindControlToGuideConverter

  • prism 命名空间

主要用途在 prism:ViewModelLocator.AutoWireViewModel="True" 这句代码,将视图 MainWindow.xamlMainWindowViewModel.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:

1fd3122e71818ed14b79547ab4b6b3a6.gif

3. 控件如何开发的?

关于原理,WPF 简易新手引导 这篇介绍的不错,可以先看看。

关于本示例的实现方式,暂时不做太多说明,详细请直接查看源码 Dotnet9WPFControls,本文后半截大概提一下。

代码组织结构如下:

57ecb2edba52a2b485511a726c0cdf3d.png
  • GuideInfo:定义引导信息类,如标题、内容、下一步按钮显示内容。

  • GuideHintControl:引导提示框控件,显示引导标题、引导内容、下一步按钮,即 GuideInfo 绑定的控件。

  • GuideControl:引导控件,用于目标控件无法获取到自己的窗体这种(即无法获取在窗体中的位置),比如您开发的程序为第三方程序插件这种,上面的代码即是使用此引导控件实现的效果。

  • GuideWindow:引导窗体,GuideControl 引导控件的相互补充。

  • GuideControlBase:引导控件辅助类

  • BindControlToGuideConverter:引导信息与引导的目标控件绑定转换器

  • GuideHelper:引导帮助类,绑定目标控件的引导信息使用,外加一个显示 引导窗体 的静态命令。

  • Guide.xaml:定义引导遮罩层(GuideControlGuideWindow)、引导提示框(GuideHintControl)样式的资源文件,定义外观请改这个文件

重点:

a) GuideControlBase

GuideControlBaseGuideControlGuideWindow 的辅助类,因为这两个类实现的功能是类似的,所以封装大部分功能在 GuideControlBase 中,比如将目标控件区域从遮罩层 Clip 出来,并将 GuideHintControl 提示框控件添加到遮罩层之上,显示出新手引导的效果。

b) GuideControl 和 GuideWindow

GuideControl 是用于显示在包含目标控件的容器内使用的,GuideControl放置的容器不一定是目标控件的直接容器,可以有嵌套,比如目标控件在ListBox子项ListBoxItem内,而引导控件GuideControl可以在ListBox的外层容器之上;

GuideWindow 用于贴在目标控件所在的窗体上,GuideWindow 作为目标控件窗体的子窗体,Show()在目标控件窗体上,不能使用ShowDialog()的方式(为啥?ShowDialog()会使除引导窗体之外的窗体处于无效状态(disable))。

这两种方式(GuideControl 和 GuideWindow)总体呈现效果是一样的,目标控件所在的窗体是自定义窗体,Demo能正常显示下面的效果,普通窗体需要对目标控件 Clip 的位置和提示框的位置进行偏移处理,修改位置见 GuideControlGuideWindow的方法 ShowGuide(FrameworkElement? targetControl, GuideInfo guide)

控件带的两个新手引导Demo如下:

新手引导Demo一

GuideControl方式,站长推荐,即以控件的方式显示新手引导,点击看代码:

5dcbb00372503c281e321f01f8eac905.gif

新手引导Demo二

GuideWindow方式,即以子窗体的方式显示新手引导,点击看代码:

0c6df124097548f3a56d67c5984cb4d2.gif

详细开发不展开说了,一切都在代码中。

4. 总结

前面写了不少,其实不多,谢谢开源带来的力量。

  • 参考文章:WPF 简易新手引导

  • 参考开源项目:AIStudio.Wpf.Controls

  • 本文Demo NewbieGuideDemo:Github、Gitee

  • Dotnet9Controls 新手引导Demo一 源码:Github、Gitee

  • Dotnet9Controls 新手引导Demo二 源码 GuideWindowView:Github、Gitee

  • Dotnet9Controls控件:Github、Gitee

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/286752.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

三、界面介绍(IVX快速手册)

三、集成开发环境界面介绍 通过本节你将了解 iVX 在线集成开发环境 界面&#xff0c;快速建立对 在线集成开发环境 的认识。 文章目录三、集成开发环境界面介绍3.1 界面区域3.2 舞台3.3 组件工具栏3.4 对象树/素材面板3.5 属性面板3.6 菜单面板3.7 逻辑工具面板3.8 辅助工具3.…

Android studio之提示Failed to resolve: com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.46

1、错误提示如下 Failed to resolve: com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.46 Show in Project Structure dialog Affected Modules: app2、解决办法 在project的build.gradle里面加入 maven { url https://jitpack.io }

【VB测绘程序设计】第二章 VB测绘程序基础

第一节 数据类型 VB中提供了以下11中基本的数据类型: 一、数值型 二、字符串 三、日期型 1.界面设计 2. 代码 <

React-引领未来的用户界面开发框架-读书笔记(六)

第12章 服务端渲染 想让搜索引擎抓取到你的站点&#xff0c;服务端渲染这一步不可或缺&#xff0c;服务端渲染还可以提升站点的性能&#xff0c;因为在加载JavaScript脚本的同时&#xff0c;浏览器就可以进行页面渲染。 React的虚拟DOM是其可被用于服务端渲染的关键。首先每个R…

TrimPath - Js模板引擎

当页面中引用template.js文件之后&#xff0c;脚本将创建一个TrimPath对象供你使用。 parseDOMTemplate(elementId,optionalDocument)  //获得模板字符串代码 得到页面中Id为elementId的DOM组件的InnerHTML&#xff0c;将其解析成一个模板&#xff0c;这个返回一个templateOb…

appserv安装

Appserv 官网: http://www.appservnetwork.com/ 安装好后&#xff0c;输入http://localhost:8082/验证是否装成功&#xff0c;成功后如下图 http://localhost:8082/ 默认指定的文件夹是 进入到phpMyAdmin 的账号是root&#xff0c;密码是安装时的密码

一、iVX简介(IVX 快速开发教程)

一、iVX简介 通过本节你将对 iVX 有一个大致的认识&#xff0c;并且了解 iVX 能够做些什么&#xff0c;有哪一些优势&#xff0c;这将帮助你更好的上手 iVX 进行应用的开发&#xff0c;初步了解 iVX 的强大之处。 文章目录一、iVX简介1.1 iVX 是什么&#xff1f;1.2 iVX适合怎…

WPF效果第一百八十六篇之又玩ListBox

大周末的接着上一篇玩耍TreeView,这二天又再次去玩耍ListBox;毕竟是我的最爱,没办法就喜欢玩耍他;闲话也不多扯了,直接看咱们最终效果:2、原来一直ItemTemplate,这次直接ListBoxItem的Template:<Setter Property"Template"><Setter.Value><ControlTem…

Android之URL “page={page}category_id={***} string For dynamic query parameters use @Query.

1、问题 我们用retrofit进行Get网络请求的时候&#xff0c;我代码是这样写的 GET("/api/get_****/***?page{page}&category_id{category_id}")suspend fun getWebsiteCategory(Path("page") page: Int, Path("category_id") category_id: …

【VB测绘程序设计】第三章 VB结构化程序设计(顺序、选择、循环)

目 录 第一节 顺序结构设计 第二节 选择结构设计 第三节 循环结构设计 第一节 顺序结构设计 一、赋值语句

React-引领未来的用户界面开发框架-读书笔记(七)

第14章 开发工具 React使用了若干的抽象层来帮助你更轻松地开发组件、推导程序状态。然而&#xff0c;在调试、构建及分发应用时&#xff0c;这样设计就会产生负面影响了。 幸运的是&#xff0c;我们拥有一些非常好的开发工具能在开发及构建过程中为我们提供帮助。在这里探讨这…

【十分钟】学会微信小游戏,攀登不止小游戏制作(IVX 快速开发教程十一)

十一、攀登不止小游戏制作 制作微信小游戏大致流程与微信小程序、Web类似&#xff0c;不同的在于是组件的使用。我们此节需要完成的小游戏需求为&#xff1a; 小球触碰矩形块会跳跃或攀爬小球触碰顶部或底部游戏结束点击屏幕将会使小球朝着该方向移动小球进行跳跃时分数会增加…

十天冲刺---Day8

站立式会议 站立式会议内容总结&#xff1a;燃尽图照片最近思考一个问题。项目是怎么进行到这一步的。算了&#xff0c;这个发在明天的冲刺总结吧。。还需继续努力&#xff0c;队友快回来快回来。。转载于:https://www.cnblogs.com/imguang/p/4965054.html

Android之去掉RecycleView和NestedScrollView边缘效果

1 问题 使用RecycleView和NestedScrollView的时候&#xff0c;滑倒顶部或者底部&#xff0c;会有边缘效果&#xff0c;就像水温波一样&#xff0c;现在需求去掉 2 解决办法 在RecycleView和NestedScrollView的xml文件里面加上如下属性即可。 android:overScrollMode"nev…

Action过滤器重构

&#xff08;注&#xff1a;本文参照 NickChapsas的Attributes get a feature long-overdue in C# 11&#xff09;今天看一个泛型特性的例子&#xff0c;这个功能在C#11才受支持。在asp.net core mvc中&#xff0c;可以给action添加filter&#xff0c;达到拦截作用&#xff0c;…

征集对Oracle的问题

两月前收到Oracle的邀请&#xff0c;10.10-16日参加在旧金山举办Oracle Open World 2009&#xff0c;旅程连上了长假。很荣幸&#xff0c;我是中国惟一入选的博客&#xff08;感谢小松and北北&#xff0c;还有小废物同学经年累月的鞭策和诱导&#xff0c;北北同学的诱导尤其受用…

一篇文学会商用可编辑问卷表单制作【iVX 十二】

公共表单 在 iVX 快速教程中&#xff0c;我们使用一个公共表单项目作为 WebApp 应用的演示说明。公共表单项目可以用于企业内部或一个问卷公共平台做问卷调查&#xff0c;用户可以自由的设置表单元素以及样式&#xff0c;并且可以手动设置表单结束下载填写问卷后的调查数据。 …

【地图学】地图投影的定义和分类

一、地图投影 1、地图投影的定义 地图投影是利用一定数学法则把地球表面的经、纬线转换到平面上的理论和方法。 2、地图投影的分类 (1)按变形性质 • 等角投影: 投影面上两微分线段的夹角与地面上的相应两线段的夹角相等,及没有角度变形的投影叫 ~ 。

React-引领未来的用户界面开发框架-读书笔记(八)

第16章 架构模式 React主要功能在于渲染HTML。可以将其看成是MVC中的V&#xff0c;它不会影响到组件中直接调用AJAX请求之类的操作&#xff1a; var TakeSurveyReact.CreateClass({getInitialData&#xff1a;function(){return{survey:null}&#xff1b;},componentDidMount:…

三)mybatis 二级缓存,整合ehcache

mybatis-config.xml <setting name"cacheEnabled" value"true" /> PersonMapper.xml <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http:…