WPF怎么做新手引导界面?

本文经原作者授权以原创方式二次分享,欢迎转载、分享。

原文作者:眾尋

原文链接:https://www.cnblogs.com/ZXdeveloper/p/8391864.html


这两天不忙,所以,做了一个简易的新手引导小Demo。因为,不是项目上应用,所以,做的很粗糙,也就是给需要的人,一个思路而已。

新手引导功能的话,就是告诉用户,页面上操作的顺序,第一步要做什么,第二步要做什么,以此类推,然后,最终关闭新手引导页面。

以我的习惯,还是先给大家看看效果。

a4af3e813b3fbb9f9c4ed752e629ebef.gif

效果展示的很简单,就是将要告诉用户操作的控件做一个提示。

要实现这个功能化,那思路就是大概以下几项:

一、遮罩窗体

将主窗体进行遮罩,半透明的效果,常用的做遮罩的话,一般是设置一个底色,然后设置透明度,类似于这篇博客 WPF透明窗体制作[1],但是,在实际的操作用就会遇到问题,如果使用正常的半透明方式的话,黄色框部分,是不发透出白色的主窗体内容的,因为已经有底色了,所以,本文使用的半透明方法是Clip的擦除,效果如下图,参考的博客WPF 用Clip属性实现蒙板特效[2]

2641326af8a69b2f4737608a6c48693e.png

先设置一个透明的窗体

<Window x:Class="SimpleGuide.GuideWin" 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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:SimpleGuide" mc:Ignorable="d" Title="GuideWin" WindowStyle="None" AllowsTransparency="True" x:Name="gw" Background="#01FFFFFF" ShowInTaskbar="False"><Grid><Border x:Name="bor" BorderBrush="White" BorderThickness="2" CornerRadius="5" Opacity="0.8"><Border.Effect><DropShadowEffect ShadowDepth="0" Color="#FF414141" BlurRadius="8" /></Border.Effect><Border Background="Black" Opacity="0.5" Margin="0" CornerRadius="5" /></Border><Canvas x:Name="can"></Canvas></Grid>
</Window>

从XAML的代码中,可以看到Background这个属性没用“Transparent”而用的是“#01FFFFFF”,因为如果用Transparent的话,那真的就是透明了,可以直接点击到主窗体里的控件,这个是我们所不希望的,所以,设置了“#01FFFFFF”,一个近乎透明的颜色。

二、显示要操作的控件

既然要对某个控件进行指引的话,那就要把控件先给圈起来,圈起来的首要任务,就是获得控件在当前窗体的坐标位置。

Point point = fe.TransformToAncestor(Window.GetWindow(fe)).Transform(new Point(0, 0));

当获取完坐标以后,则需要将控件给圈起来,我的方法,就是取当前的坐标-5,宽和高+10,来绘制一个空白的区域,其实,这个部分应该是指擦除

RectangleGeometry rg1 = new RectangleGeometry();
rg1.Rect = new Rect(point.X - 5, point.Y - 5, fe.ActualWidth + 10, fe.ActualHeight + 10);
borGeometry = Geometry.Combine(borGeometry, rg1, GeometryCombineMode.Exclude, null);

三、绘制一个指引的UC

指引UC,设计起来就比较方便了,样子其实挺简单的

4eeef69d507c5343386bfbae87b3373b.png

就是用Path,绘制一个范围,但是虚线框,最开始的想法是用Line去做,但是感觉太费事了,就直接用的StrokeDashArray这个属性,Stroke是Path本身的边框线,当然,真的是边框,所以,又不好设置Margin或者Padding,所以,最后的做法,就是,在外层又绘制了一个区域,只是这个区域不包含边框线而已,填充色相同

<Path Fill="#FF2FBEED"><Path.Data><GeometryGroup><PathGeometry Figures="M 8,22 A 12,12 0 1 1 22,8 L 102 8 L 102 62 L 8 62 Z" /></GeometryGroup></Path.Data>
</Path>
<Path StrokeThickness="1" Stroke="White" StrokeDashArray="2,1" Fill="#FF2FBEED"><Path.Data><GeometryGroup><PathGeometry Figures="M 10,20 A 10,10 0 1 1 20,10 L 100 10 L 100 60 L 10 60 Z" /></GeometryGroup></Path.Data>
</Path>

显示内容的部分是一个Textblock,当时遇到了一个问题,就是换行问题,Textblock必须要有Width,才会换行,但是由于最外层是Viewbox,所以,尝试过获取UC的Width或者ActualWidth,都不行,所以,最后的解决办法是,传入一个窗体的宽度和高度进来,而不是在外部设置此UC的宽和高。

public HintUC(string xh, string content, Visibility vis = Visibility.Visible, int width = 260, int height = 160)
{InitializeComponent();this.Width = width;this.Height = height;this.tb_nr.Width = width / 4;this.tb_xh.Text = xh;this.tb_nr.Text = content;this.btn_next.Visibility = vis;
}

四、下一步的触发

触发下一步,相当于是子控件调用主控件的事件,这样的话,就是写一个委托,在主窗体里去实现具体的方法。

private void show(int xh, FrameworkElement fe, string con, Visibility vis = Visibility.Visible)
{Point point = fe.TransformToAncestor(Window.GetWindow(fe)).Transform(new Point(0, 0));//获取控件坐标点RectangleGeometry rg = new RectangleGeometry();rg.Rect = new Rect(0, 0, this.Width, this.Height);borGeometry = Geometry.Combine(borGeometry, rg, GeometryCombineMode.Union, null);bor.Clip = borGeometry;RectangleGeometry rg1 = new RectangleGeometry();rg1.Rect = new Rect(point.X - 5, point.Y - 5, fe.ActualWidth + 10, fe.ActualHeight + 10);borGeometry = Geometry.Combine(borGeometry, rg1, GeometryCombineMode.Exclude, null);bor.Clip = borGeometry;HintUC hit = new HintUC(xh.ToString(), con, vis);Canvas.SetLeft(hit, point.X + fe.ActualWidth + 3);Canvas.SetTop(hit, point.Y + fe.ActualHeight + 3);hit.nextHintEvent -= Hit_nextHintEvent;hit.nextHintEvent += Hit_nextHintEvent;can.Children.Add(hit);index++;
}
private void Hit_nextHintEvent()
{if (list[index - 1] != null){can.Children.Clear();}if (index == list.Count - 1)show(index + 1, list[index].Uc, list[index].Content, Visibility.Collapsed);elseshow(index + 1, list[index].Uc, list[index].Content);
}

我们要在外部声明一个index的变量来记录当前的List集合的索引,首先要判断,当前的内容里,是否不为空,如果是的话,要清除掉,如果不清除的话,就会看到一堆的提示框,然后,判别是否是List集合里的最后一个控件了,如果是的话,那就不再显示“下一步按钮了”。

五、扩展部分

由于是一个小Demo,所以发现了一些问题,但是就没有再解决了,例如如果主窗体不是无边框的话,取值定位会有问题。

这是由于弹出的引导窗体获取了主窗体的大小,但是Point去获取控件坐标位置的时候,主窗体是不包含头部的,由于遮罩没有头部,所以定位出错了,这个我还没有找到好的解决办法,如果有大神知道如何解决的话,请赐教,谢谢了。

ff325472a040420a815833d129c55c31.png

显示引导内容的部分,也可以换成一个Grid,这样的话,就可以传入UserControl了,有兴趣的朋友可以自行修改。

源码:Demo[3]

站长使用体验

效果确实不错,站长通过原作者的源码改了一点(代码[4]),需要遮罩的控件换成Image控件也是相同效果,nice:

139908c62c5e432efa970779b7159e03.gif

参考资料

[1]

WPF透明窗体制作: http://blog.csdn.net/cmis7645/article/details/7781990

[2]

WPF 用Clip属性实现蒙板特效: http://blog.csdn.net/feitiankoulan/article/details/25201593

[3]

Demo: https://files.cnblogs.com/files/ZXdeveloper/SimpleGuide.zip

[4]

代码: https://github.com/dotnet9/TerminalMACS.ManagerForWPF/tree/master/src/Demo/SimpleGuide

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

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

相关文章

《看聊天记录都学不会C语言?太菜了吧》(19)巩固开始,数字1、2、3、4能够组成多少个 3 位数的不同的排列

若是大一学子或者是真心想学习刚入门的小伙伴可以私聊我&#xff0c;若你是真心学习可以送你书籍&#xff0c;指导你学习&#xff0c;给予你目标方向的学习路线&#xff0c;无套路&#xff0c;博客为证。 本系列文章将会以通俗易懂的对话方式进行教学&#xff0c;对话中将涵盖…

【经典回放】多种语言系列数据结构算法:串(C版)

我们这里说的串、就是标准的C语言的串,这点,和我们教材中另行定义的串并不一致。我们这里强调仅仅是按C语言的标准处理串,是因为你会按C语言的标准构造串、而不是按其它的模式定义的。在我们的教材上,串相当与一个: struct ElemType {char *str; }; 构造的顺序表、或者是…

可以只读的 ServiceCollection

可以只读的 ServiceCollectionIntro在 .NET 7 Preview 4 中&#xff0c;ServiceCollection 可以声明为只读了&#xff0c;这使得我们可以有效避免在构建了 ServiceProvider 之后再新增服务&#xff0c;导致服务注册失败。Sample在新的版本中&#xff0c;ServiceCollection 新增…

阿里云与中国联通首个公共云平台上线

11月8日&#xff0c;阿里云与中国联通关于公共云合作的首个项目&#xff1a;浙江联通“沃云Powered by Alibaba cloud” 平台&#xff08;cloud.10010zj.com.cn&#xff09;正式发布上线。该平台将以沃云品牌为客户提供“阿里云联通”服务&#xff0c;结合阿里云技术及浙江联通…

IBM X System ServerGuide 8.41 服务器 系统安装 引导盘

IBM X System ServerGuide 8.41 支持操作系统: 32位: Microsoft Windows 2003/2003 R2 (Enterprise, Standard, Web and DataCenter UV) Microsoft Small Business Server 2003/2003 R2 (Standard/Premium Edition) Microsoft Windows 2008 (Enterprise, Standard, Web and Dat…

Matlab R2018b简体中文版完整安装图文教程(附安装包下载)

目 录 一、安装过程 二、下载地址 matlab R2018b安装包如下所示,包括主程序和补丁文件两部分。 一、安装过程 双击安装包中的setup.exe。 选择使用文件安装MIYAO,点击下一步。

《看聊天记录都学不会C语言?太菜了吧》(20)(必懂!题解)我能知道2000年后的这个月一共有几天

若是大一学子或者是真心想学习刚入门的小伙伴可以私聊我&#xff0c;若你是真心学习可以送你书籍&#xff0c;指导你学习&#xff0c;给予你目标方向的学习路线&#xff0c;无套路&#xff0c;博客为证。 本系列文章将会以通俗易懂的对话方式进行教学&#xff0c;对话中将涵盖…

linux nginx线程池,nginx使用线程池提升9倍性能

众所周知nginx使用异步&#xff0c;事件驱动方法处理连接。这意味着nginx使用一个worker进程处理多个连接和请求&#xff0c;而不是每一个请求有一个专门的进程或着线程处理(像传统架构的服务器那样&#xff0c;例如apache)。为了实现这个目的&#xff0c;nginx使用非阻塞模式的…

Android之解决androidx.appcompat.widget.Toolbar去掉左边距

1 问题 androidx.appcompat.widget.Toolbar默认左边有间距 2 解决办法 在Toolbar下面添加如下熟悉 app:contentInsetLeft"0dp"app:contentInsetStart"0dp"app:contentInsetEnd"0dp"app:maxButtonHeight"20dp"app:titleMargin"0…

C# 配置日志记录

在 .NET Core 中&#xff0c;可以给配置文件使用提供程序&#xff0c;例如从 JSON 或 XML文件、环境变量或命令行参数中读取配置。只需要从 NuGet 包 Microsoft.ExtensionsConfiguration 中创建一个ConfigurationBuilder&#xff0c;并向此构建器添加提供程序。要添加 JSON 提供…

使用“using” 的 “Cursor”

很多时候&#xff0c;我们会写下面的这段代码&#xff1a; private void button1_Click(object sender, EventArgs e) {Cursor cursor Cursor.Current;this.Cursor Cursors.WaitCursor;LongTimeMethod();this.Cursor cursor; }private void LongTimeMethod() {for (int i 0…

《看聊天记录都学不会C语言?太菜了吧》(21)(必懂!题解)在现实生活中,打擂台比赛争名次竟用的是冒泡排序?

若是大一学子或者是真心想学习刚入门的小伙伴可以私聊我&#xff0c;若你是真心学习可以送你书籍&#xff0c;指导你学习&#xff0c;给予你目标方向的学习路线&#xff0c;无套路&#xff0c;博客为证。 本系列文章将会以通俗易懂的对话方式进行教学&#xff0c;对话中将涵盖…

ArcGIS 10.7如何获取矢量多边形所有折点的坐标(平面坐标和经纬度坐标)?

Descriptions:As shown in the figure below is a surface pattern spot, how to obtain the coordinates of each vertex (plane coordinates and latitude and longitude coordinates)? The results we want are as follows: Via data source,we get the information that…

Mahout分类算法学习之实现Naive Bayes分类示例

1.简介 (1) 贝叶斯分类器的分类原理发源于古典概率理论&#xff0c;是通过某对象的先验概率&#xff0c;利用贝叶斯公式计算出其后验概率&#xff0c;即该对象属于某一类的概率&#xff0c;选择具有最大后验概率的类作为该对象所属的类。朴素贝叶斯分类器(Naive Bayes Classifi…

一维条形码***技术(Badbarcode)

【转】http://future-sec.com/badbarcode.html 前言在日常生活中&#xff0c;条形码随处可见&#xff0c;特别在超市&#xff0c;便利店&#xff0c;物流业&#xff0c;但你们扫的条形码真的安全吗&#xff1f;之前TK教主在PacSec介绍的条形码攻击和twitter上的demo视频太炫酷&…

ArcGIS 10.7 模型构建器Model Builder空间建模流程化作业案例----影像拼接与掩膜裁剪

Model Builder(模型构建器)是一个用来创建、编辑和管理空间分析模型的应用程序,是一种可视化的编程环境,通过对现有工具的组合完成新模型或软件的制作,为设计和实现空间处理模型(包括工具、脚本和数据)提供了一个图形化的模型框架。 本文以影像数据的拼接和掩膜裁剪为例…

Hello Playwright:(4)自动化测试

利用 Playwright 提供的 API&#xff0c;我们在浏览器上做的很多事情都可以自动化。例如&#xff0c;搜索数据、填写表单和下载文件等等。但最适合的工作&#xff0c;就是自动化测试 Web 应用程序。自动化测试测试是软件开发中的一项基本任务&#xff0c;至少&#xff0c;你需要…

ArcGIS 10.7拆分多部件要素(Multipart Features)至单部件要素的两种方法

GIS中经常会出现多部件要素的现象,为了便于检查拓扑等关系,需要将其拆分为单个的部件。例如,在用同一个图层的多个图斑去裁剪(Clip)时,或者将多个不相邻的图斑进行合并(merge)时,可能会产生多部件要素,本文演示ArcGIS10.7版本中常见的两种拆分多部件要素至单部件要素…

spring-session + redis 实现集群 session 共享

2019独角兽企业重金招聘Python工程师标准>>> 目前市面上实现session共享的方案有很多&#xff0c;其中比较常用的是使用Tomcat、Jetty等web服务器提供的session共享功能&#xff0c;以此将session内容统一存放在数据库&#xff08;如mysql&#xff09;或者缓存&…

《看聊天记录都学不会Python到游戏实战?太菜了吧》(10)无底洞的循环

本系列文章将会以通俗易懂的对话方式进行教学&#xff0c;对话中将涵盖了新手在学习中的一般问题。此系列将会持续更新&#xff0c;包括别的语言以及实战都将使用对话的方式进行教学&#xff0c;基础编程语言教学适用于零基础小白&#xff0c;之后实战课程也将会逐步更新。 若…