WPF实现新手引导
1. 半透明灰的遮罩层
- 新建一个遮盖的window窗体
- canvas是后期可以在思显示高亮区域
//定义一个window将它的样式设置透明等可以覆盖到其他窗体上,其中遮罩层使用border控件
//原因
//1. 支持圆角和方向可以适应不同的窗体样式 2. 支持阴影效果
<Grid Background="#01000000" MouseLeftButtonDown="Grid_MouseLeftButtonDown">
<Border x:Name="border">
<Border Margin="0"
Background="#000000"
Opacity="0.5" />
</Border>
<Canvas x:Name="canvas" />
</Grid>
2. 汽包的设置
- 建一个"自定义控件(UserControl)"设置自定义汽包样式
- 规划好样式设置
点击查看代码
<Grid>
<Grid.RowDefinitions>
<RowDefinition x:Name="row1" />
<RowDefinition x:Name="row2" Height="auto" />
<RowDefinition x:Name="row3" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="colum1" />
<ColumnDefinition x:Name="colum2" Width="auto" />
<ColumnDefinition x:Name="colum3" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Row="1"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Orientation="Horizontal">
<Grid>
<Ellipse Width="20"
Height="20"
Fill="White"
Opacity="0.5" />
<Ellipse Width="10"
Height="10"
HorizontalAlignment="Center"
Fill="White" />
</Grid>
<Line Height="2"
VerticalAlignment="Center"
Stroke="White"
StrokeDashArray="2,1"
StrokeThickness="2"
X1="0"
X2="30"
Y1="0"
Y2="0" />
<Path Height="12"
VerticalAlignment="Center"
Data="M 10,0 0,6 10,12 Z"
Fill="White" />
</StackPanel>
<StackPanel Grid.Column="1"
VerticalAlignment="Bottom"
Orientation="Vertical">
<Grid>
<Ellipse Width="20"
Height="20"
Fill="White"
Opacity="0.5" />
<Ellipse Width="10"
Height="10"
HorizontalAlignment="Center"
Fill="White" />
</Grid>
<Line Width="2"
HorizontalAlignment="Center"
Stroke="White"
StrokeDashArray="2,1"
StrokeThickness="2"
X1="2"
X2="2"
Y1="0"
Y2="30" />
<Path HorizontalAlignment="Center"
Data="M 0,10 6,0 12,10 Z"
Fill="White" />
</StackPanel>
<StackPanel Grid.Row="1"
Grid.Column="2"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Orientation="Horizontal">
<Path Height="12"
VerticalAlignment="Center"
Data="M 0,0 10,6 0,12 Z"
Fill="White" />
<Line Height="1"
VerticalAlignment="Center"
Stroke="White"
StrokeDashArray="2,1"
StrokeThickness="2"
X1="0"
X2="30"
Y1="0"
Y2="0" />
<Grid>
<Ellipse Width="20"
Height="20"
Fill="White"
Opacity="0.5" />
<Ellipse Width="10"
Height="10"
HorizontalAlignment="Center"
Fill="White" />
</Grid>
</StackPanel>
<StackPanel Grid.Row="2"
Grid.Column="1"
VerticalAlignment="Top"
Orientation="Vertical">
<Path HorizontalAlignment="Center"
Data="M 0,0 6,10 12,0 Z"
Fill="White" />
<Line Width="2"
HorizontalAlignment="Center"
Stroke="White"
StrokeDashArray="2,1"
StrokeThickness="2"
X1="2"
X2="2"
Y1="0"
Y2="30" />
<Grid>
<Ellipse Width="20"
Height="20"
Fill="White"
Opacity="0.5" />
<Ellipse Width="10"
Height="10"
HorizontalAlignment="Center"
Fill="White" />
</Grid>
</StackPanel>
<Border Grid.Row="1"
Grid.Column="1"
Padding="10"
Background="White"
CornerRadius="5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<TextBlock x:Name="txtNum"
HorizontalAlignment="Left"
FontSize="12"
FontWeight="Regular"
Foreground="#666666 ">
<Run Text="1" />
<Run Text="/" />
<Run Text="3" />
</TextBlock>
<aps:ImageButton Margin="-13,-3,-15,0"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Background="White"
Click="Close_Click"
HoverImage="/Resources/Images/Close_Hover.svg"
ImageHeight="9"
ImageWidth="9"
NormalImage="/Resources/Images/Close.svg"
PressedImage="/Resources/Images/Close_Pressed.svg" />
<TextBox Grid.Row="1"
MaxWidth="190"
Margin="10"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="Transparent"
BorderThickness="0"
Cursor="Arrow"
FontSize="14"
FontWeight="Regular"
Foreground="#333333 "
IsReadOnly="True"
Text="提示的语句"
TextWrapping="Wrap" />
<Button Grid.Row="2"
Height="30"
MinWidth="100"
Padding="10,5"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Click="Next_Click"
Content="按钮的内容"
FontSize="12"
Foreground="#FFFFFF " />
</Grid>
</Border>
</Grid>
3. 汽包出现的位置
- 通过TransformToAncestor方法拿到控件坐标之后从左上角(0,0)点的位置在带入控件的宽高计算出起点的坐标
点击查看代码
//汽包应该显示在那个位置
public void StartGuide(GuideModel guide) {
//这个是拿到自定义控件
var focusElemt = guide.UserControl;
var window = Window.GetWindow(focusElemt);
var point = focusElemt.TransformToAncestor(window).Transform(new Point(0, 0));
var rectangleGeometry = new RectangleGeometry();
rectangleGeometry.Rect = new Rect(0, 0, this.Width, this.Height);
borderGeometry = Geometry.Combine(borderGeometry, rectangleGeometry, GeometryCombineMode.Union, null);
var rectangleGeometry1 = new RectangleGeometry();
//自适应一下
rectangleGeometry1.Rect = new Rect(point.X - 5, point.Y - 5, focusElemt.ActualWidth + 10, focusElemt.ActualHeight + 10);
rectangleGeometry1.RadiusX = 5;
rectangleGeometry1.RadiusY = 5;
borderGeometry = Geometry.Combine(borderGeometry, rectangleGeometry1, GeometryCombineMode.Exclude, null);
border.Clip = borderGeometry;
//将初始化完的汽包传进来
InitHintControl(guide, point);
//实现步骤的一个累加
currentStep++;
}初始化汽包
new一个新的对象传入自定义控件“Steptip”以及传入对应的参数
private async void InitHintControl(GuideModel guideModel, Point point) {
//传入对应的参数
stepTip = new StepTip(guideModel.ArrowDirection, guideModel.TipText, guideModel.ButtonContent, guideModel.Step, guideModel.TotalStep);
//这个是解决“步骤引导”每个都从左上角(0,0)开始寻找 这个是让它寻找完后再显示出来
stepTip.Visibility = Visibility.Hidden;
stepTip.OnNext += StepTip_OnNext;
stepTip.OnClosed += StepTip_OnClosed;
canvas.Children.Add(stepTip);
//防止未生成
await Task.Delay(50);
//对自定义控件每个方向的确定 寻找以及位置的显示的高亮区域
switch (guideModel.ArrowDirection) {
case StepTip.Direction.Top:
Canvas.SetLeft(stepTip, point.X + 5 - ((stepTip.ActualWidth - guideModel.UserControl.ActualWidth) / 2));
Canvas.SetTop(stepTip, point.Y + 5 + guideModel.UserControl.ActualHeight);
break;
case StepTip.Direction.Bottom:
Canvas.SetLeft(stepTip, point.X + ((guideModel.UserControl.ActualWidth - stepTip.ActualWidth) / 2));
Canvas.SetBottom(stepTip, this.ActualHeight - point.Y + 5);
break;
case StepTip.Direction.Left:
Canvas.SetLeft(stepTip, point.X + 5 + guideModel.UserControl.ActualWidth);
Canvas.SetTop(stepTip, point.Y + 5 + ((guideModel.UserControl.ActualHeight - stepTip.ActualHeight) / 2));
break;
case StepTip.Direction.Right:
Canvas.SetLeft(stepTip, point.X-5 - stepTip.ActualWidth);
Canvas.SetTop(stepTip, point.Y + 5 + ((guideModel.UserControl.ActualHeight - stepTip.ActualHeight) / 2));
break;
default:
break;
}
stepTip.Visibility = Visibility.Visible;
}
步骤的下一步进行与关闭操作
点击查看代码
private void StepTip_OnClosed() {
this.Close();
MainWindow.Instance.Activate();
}
private void StepTip_OnNext() {
if (guideWindows.Count == 0)
return;
var beforGuide = guideWindows[currentStep - 1];
if (guideWindows.Count == currentStep) {
EndStep();
return;
}
var currentGuide = guideWindows[currentStep];
if (beforGuide != null) {
canvas.Children.Clear();
}
if (currentGuide != null) {
StartGuide(currentGuide);
}
}
实行如何找到要提示的内容
- 在要执行的页面建一个“Loaded”事件
- 初始化InitGuideWindow();
点击查看代码
private void EditPage_Loaded(object sender, RoutedEventArgs e) {
InitGuideWindow();
}
private void InitGuideWindow() {
var allGuide = new List<GuideModel>();
allGuide.AddRange(InitWelecome());
var akkGuides = allGuide.OrderBy(i => i.Step).ToList();
guideWindow = new GuideWindow(MainWindow.Instance, akkGuides);
guideWindow.Owner = MainWindow.Instance;
guideWindow.ShowDialog();
}
}
//寻找控件
List<GuideModel> InitWelecome() {
var lstWelecome = new List<GuideModel>();
var findCtrl = ControlHelper.FindControl<StackPanel>("optionPanel", optionGrid);
var createModel = new GuideModel() {
Step = 1,
TipText = LangEx.Get("MoreFeatures"),
UserControl = findCtrl,
ArrowDirection = Controls.StepTip.Direction.Left,
TotalStep = 3,
ButtonContent = LangEx.Get("Know")
};
lstWelecome.Add(createModel); var findCtrl1 = ControlHelper.FindControl<Button>("btnSave", panelWorkspace);
var createModel1 = new GuideModel() {
Step = 3,
TipText = LangEx.Get("SaveMattingResults"),
UserControl = findCtrl1,
ArrowDirection = Controls.StepTip.Direction.Bottom,
TotalStep = 3,
ButtonContent = LangEx.Get("Know")
};
lstWelecome.Add(createModel1);
var findCtrl2 = ControlHelper.FindControl<Button>("btnSetting", MainWindow.Instance);
findCtrl2.Margin = new Thickness(10, 0,10, 0);
var createModel2 = new GuideModel() {
Step = 2,
TipText = LangEx.Get("PromptStorageLocation"),
UserControl = findCtrl2,
ArrowDirection = Controls.StepTip.Direction.Top,
TotalStep = 3,
ButtonContent = LangEx.Get("Know")
};
lstWelecome.Add(createModel2);
return lstWelecome;
}
WPF实现新手引导的更多相关文章
- WPF 简易新手引导
这两天不忙,所以,做了一个简易的新手引导小Demo.因为,不是项目上应用,所以,做的很粗糙,也就是给需要的人,一个思路而已. 新手引导功能的话,就是告诉用户,页面上操作的顺序,第一步要做什么,第二步要 ...
- WPF|快速添加新手引导功能(支持MVVM)
阅读导航 前言 案例一 案例二 案例三(本文介绍的方式) 如何使用? 控件如何开发的? 总结 1. 前言 案例一 站长分享过 眾尋 大佬的一篇 WPF 简易新手引导 一文,新手引导的效果挺不错的,如下 ...
- WPF 新手引导
参考了https://www.cnblogs.com/ZXdeveloper/p/8391864.html,自己随便实现了一个,记录下,比较丑 <Window x:Class="Use ...
- 在WPF中使用依赖注入的方式创建视图
在WPF中使用依赖注入的方式创建视图 0x00 问题的产生 互联网时代桌面开发真是越来越少了,很多应用都转到了浏览器端和移动智能终端,相应的软件开发上的新技术应用到桌面开发的文章也很少.我之前主要做W ...
- MVVM框架从WPF移植到UWP遇到的问题和解决方法
MVVM框架从WPF移植到UWP遇到的问题和解决方法 0x00 起因 这几天开始学习UWP了,之前有WPF经验,所以总体感觉还可以,看了一些基础概念和主题,写了几个测试程序,突然想起来了前一段时间在W ...
- MVVM模式解析和在WPF中的实现(六) 用依赖注入的方式配置ViewModel并注册消息
MVVM模式解析和在WPF中的实现(六) 用依赖注入的方式配置ViewModel并注册消息 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二 ...
- MVVM模式解析和在WPF中的实现(五)View和ViewModel的通信
MVVM模式解析和在WPF中的实现(五) View和ViewModel的通信 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 M ...
- MVVM设计模式和WPF中的实现(四)事件绑定
MVVM设计模式和在WPF中的实现(四) 事件绑定 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在WPF中 ...
- MVVM模式解析和在WPF中的实现(三)命令绑定
MVVM模式解析和在WPF中的实现(三) 命令绑定 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在WPF中 ...
- MVVM模式和在WPF中的实现(二)数据绑定
MVVM模式解析和在WPF中的实现(二) 数据绑定 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在WPF中 ...
随机推荐
- LeetCode 周赛 338,贪心 / 埃氏筛 / 欧氏线性筛 / 前缀和 / 二分查找 / 拓扑排序
本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问. 大家好,我是小彭. 上周末是 LeetCode 第 338 场周赛,你参加了吗?这场周赛覆盖的知识点很多,第 ...
- Sokit(TCP/UDP调试工具)
下载:http://www.winwin7.com/soft/56522.html#xiazai Sokit中文版是一款免费开源的TCP / UDP 测试(调试)工具,它主要可以用于接收和发送TCP/ ...
- 机器学习(三):朴素贝叶斯+贝叶斯估计+BP人工神经网络习题手算|手工推导与习题计算
1.有 1000 个水果样例. 它们可能是香蕉,橙子或其它水果,已知每个水果的 3 种特性:是否偏长.是否甜.颜色是否是黄色 类型 长 不长 甜 不甜 黄色 非黄 Total 香蕉 400 100 3 ...
- MySQL日志机制分析
进入正题前先简单看看MySQL的逻辑架构,相信我用的着. MySQL的逻辑架构大致可以分为三层: 第一层:处理客户端连接.授权认证,安全校验等. 第二层:服务器server层,负责对SQL解释.分析. ...
- selenium之文件的上传
文件的上传:主要是两种实现方法: 1.如果定位的元素是type类型是file类型的话,那么直接定位元素并使用send_keys方法完成文件上传 2.如果是非file类型的话,则需要使用第三方工具完成文 ...
- Dijkstra(迪杰斯特拉)算法C++实现&讲解
Dijkstra迪杰斯特拉算法及C++实现 Dijkstra算法是典型的最短路径路由算法,用来计算一个节点到其他所有节点的最短路径.算法的基本思想和流程是:1. 初始化出发点到其它各点的距离dist[ ...
- R语言文本数据挖掘(三)
文本分词,就是对文本进行合理的分割,从而可以比较快捷地获取关键信息.例如,电商平台要想了解更多消费者的心声,就需要对消费者的文本评论数据进行内在信息的数据挖掘分析,而文本分词是文本挖掘的重要步骤.R语 ...
- Python之进程管理
使用python创建进程 from multiprocessing import Process # 导入进程模块 import time # 定义一个函数,测试创建进程使用 def task(nam ...
- Notion AI:门槛更低的ChatGPT Plus
[2023年3月27日]由于接口成本的问题,如今的大部分应用应该都只会建立在GPT-3/ChatGPT接口的基础上,所以想要体验GPT-4,还是得尊贵的ChatGPT Plus. 前段日子体验了Not ...
- 五月十四号java基础知识点
class Person{ private String name; private int age; public Person(String name,int age){ this.name = ...