- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章WPF图形解锁控件ScreenUnLock使用详解由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
ScreenUnLock 与智能手机上的图案解锁功能一样。通过绘制图形达到解锁或记忆图形的目的.
本人突发奇想,把手机上的图形解锁功能移植到WPF中。也应用到了公司的项目中.
在创建ScreenUnLock之前,先来分析一下图形解锁的实现思路.
1.创建九宫格原点(或更多格子),每个点定义一个坐标值 。
2.提供图形解锁相关扩展属性和事件,方便调用者定义。比如:点和线的颜色(Color),操作模式(Check|Remember),验证正确的颜色(RightColor), 验证失败的颜色(ErrorColor), 解锁事件 OnCheckedPoint,记忆事件 OnRememberPoint 等,
3.定义MouseMove事件监听画线行为。 画线部分也是本文的核心。在画线过程中。程序需判断,线条从哪个点开始绘制,经过了哪个点(排除已经记录的点)。是否完成了绘制等等.
4.画线完成,根据操作模式处理画线完成行为。并调用相关自定义事件 。
大致思路如上,下面开始一步一步编写ScreenUnLock吧 。
创建ScreenUnLock 。
1
|
public
partial
class
ScreenUnlock : UserControl
|
定义相关属性 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
/// <summary>
/// 验证正确的颜色
/// </summary>
private
SolidColorBrush rightColor;
/// <summary>
/// 验证失败的颜色
/// </summary>
private
SolidColorBrush errorColor;
/// <summary>
/// 图案是否在检查中
/// </summary>
private
bool
isChecking;
public
static
readonly
DependencyProperty PointArrayProperty = DependencyProperty.Register(
"PointArray"
,
typeof
(IList<
string
>),
typeof
(ScreenUnlock));
/// <summary>
/// 记忆的坐标点
/// </summary>
public
IList<
string
> PointArray
{
get
{
return
GetValue(PointArrayProperty)
as
IList<
string
>; }
set
{ SetValue(PointArrayProperty, value); }
}
/// <summary>
/// 当前坐标点集合
/// </summary>
private
IList<
string
> currentPointArray;
/// <summary>
/// 当前线集合
/// </summary>
private
IList<Line> currentLineList;
/// <summary>
/// 点集合
/// </summary>
private
IList<Ellipse> ellipseList;
/// <summary>
/// 当前正在绘制的线
/// </summary>
private
Line currentLine;
public
static
readonly
DependencyProperty OperationPorperty = DependencyProperty.Register(
"Operation"
,
typeof
(ScreenUnLockOperationType),
typeof
(ScreenUnlock),
new
FrameworkPropertyMetadata(ScreenUnLockOperationType.Remember));
/// <summary>
/// 操作类型
/// </summary>
public
ScreenUnLockOperationType Operation
{
get
{
return
(ScreenUnLockOperationType)GetValue(OperationPorperty); }
set
{ SetValue(OperationPorperty, value); }
}
public
static
readonly
DependencyProperty PointSizeProperty = DependencyProperty.Register(
"PointSize"
,
typeof
(
double
),
typeof
(ScreenUnlock),
new
FrameworkPropertyMetadata(15.0));
/// <summary>
/// 坐标点大小
/// </summary>
public
double
PointSize
{
get
{
return
Convert.ToDouble(GetValue(PointSizeProperty)); }
set
{ SetValue(PointSizeProperty, value); }
}
public
static
readonly
DependencyProperty ColorProperty = DependencyProperty.Register(
"Color"
,
typeof
(SolidColorBrush),
typeof
(ScreenUnlock),
new
FrameworkPropertyMetadata(
new
SolidColorBrush(Colors.White),
new
PropertyChangedCallback((s, e) =>
{
(s
as
ScreenUnlock).Refresh();
})));
/// <summary>
/// 坐标点及线条颜色
/// </summary>
public
SolidColorBrush Color
{
get
{
return
GetValue(ColorProperty)
as
SolidColorBrush; }
set
{ SetValue(ColorProperty, value); }
}
/// <summary>
/// 操作类型
/// </summary>
public
enum
ScreenUnLockOperationType
{
Remember = 0, Check = 1
}
|
初始化ScreenUnLock 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
public
ScreenUnlock()
{
InitializeComponent();
this
.Loaded += ScreenUnlock_Loaded;
this
.Unloaded += ScreenUnlock_Unloaded;
this
.MouseMove += ScreenUnlock_MouseMove;
//监听绘制事件
}
private
void
ScreenUnlock_Loaded(
object
sender, RoutedEventArgs e)
{
isChecking =
false
;
rightColor =
new
SolidColorBrush(Colors.Green);
errorColor =
new
SolidColorBrush(Colors.Red);
currentPointArray =
new
List<
string
>();
currentLineList =
new
List<Line>();
ellipseList =
new
List<Ellipse>();
CreatePoint();
}
private
void
ScreenUnlock_Unloaded(
object
sender, RoutedEventArgs e)
{
rightColor =
null
;
errorColor =
null
;
if
(currentPointArray !=
null
)
this
.currentPointArray.Clear();
if
(currentLineList !=
null
)
this
.currentLineList.Clear();
if
(ellipseList !=
null
)
ellipseList.Clear();
this
.canvasRoot.Children.Clear();
}
|
创建点 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
/// <summary>
/// 创建点
/// </summary>
private
void
CreatePoint()
{
canvasRoot.Children.Clear();
int
row = 3, column = 3;
//三行三列,九宫格
double
oneColumnWidth = (
this
.ActualWidth == 0 ?
this
.Width :
this
.ActualWidth) / 3;
//单列的宽度
double
oneRowHeight = (
this
.ActualHeight == 0 ?
this
.Height :
this
.ActualHeight) / 3;
//单列的高度
double
leftDistance = (oneColumnWidth - PointSize) / 2;
//单列左边距
double
topDistance = (oneRowHeight - PointSize) / 2;
//单列上边距
for
(var i = 0; i < row; i++)
{
for
(var j = 0; j < column; j++)
{
Ellipse ellipse =
new
Ellipse()
{
Width = PointSize,
Height = PointSize,
Fill = Color,
Tag =
string
.Format(
"{0}{1}"
, i, j)
};
Canvas.SetLeft(ellipse, j * oneColumnWidth + leftDistance);
Canvas.SetTop(ellipse, i * oneRowHeight + topDistance);
canvasRoot.Children.Add(ellipse);
ellipseList.Add(ellipse);
}
}
}
|
创建线 。
1
2
3
4
5
6
7
8
9
|
private
Line CreateLine()
{
Line line =
new
Line()
{
Stroke = Color,
StrokeThickness = 2
};
return
line;
}
|
点和线都创建都定义好了,可以开始监听绘制事件了 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
private
void
ScreenUnlock_MouseMove(
object
sender, System.Windows.Input.MouseEventArgs e)
{
if
(isChecking)
//如果图形正在检查中,不响应后续处理
return
;
if
(e.LeftButton == System.Windows.Input.MouseButtonState.Pressed)
{
var point = e.GetPosition(
this
);
HitTestResult result = VisualTreeHelper.HitTest(
this
, point);
Ellipse ellipse = result.VisualHit
as
Ellipse;
if
(ellipse !=
null
)
{
if
(currentLine ==
null
)
{
//从头开始绘制
currentLine = CreateLine();
var ellipseCenterPoint = GetCenterPoint(ellipse);
currentLine.X1 = currentLine.X2 = ellipseCenterPoint.X;
currentLine.Y1 = currentLine.Y2 = ellipseCenterPoint.Y;
currentPointArray.Add(ellipse.Tag.ToString());
Console.WriteLine(
string
.Join(
","
, currentPointArray));
currentLineList.Add(currentLine);
canvasRoot.Children.Add(currentLine);
}
else
{
//遇到下一个点,排除已经经过的点
if
(currentPointArray.Contains(ellipse.Tag.ToString()))
return
;
OnAfterByPoint(ellipse);
}
}
else
if
(currentLine !=
null
)
{
//绘制过程中
currentLine.X2 = point.X;
currentLine.Y2 = point.Y;
//判断当前Line是否经过点
ellipse = IsOnLine();
if
(ellipse !=
null
)
OnAfterByPoint(ellipse);
}
}
else
{
if
(currentPointArray.Count == 0)
return
;
isChecking =
true
;
if
(currentLineList.Count + 1 != currentPointArray.Count)
{
//最后一条线的终点不在点上
//两点一线,点的个数-1等于线的条数
currentLineList.Remove(currentLine);
//从已记录的线集合中删除最后一条多余的线
canvasRoot.Children.Remove(currentLine);
//从界面上删除最后一条多余的线
currentLine =
null
;
}
if
(Operation == ScreenUnLockOperationType.Check)
{
Console.WriteLine(
"playAnimation Check"
);
var result = CheckPoint();
//执行图形检查
//执行完成动画并触发检查事件
PlayAnimation(result, () =>
{
if
(OnCheckedPoint !=
null
)
{
this
.Dispatcher.BeginInvoke(OnCheckedPoint,
this
,
new
CheckPointArgs() { Result = result });
//触发检查完成事件
}
});
}
else
if
(Operation == ScreenUnLockOperationType.Remember)
{
Console.WriteLine(
"playAnimation Remember"
);
RememberPoint();
//记忆绘制的坐标
var args =
new
RememberPointArgs() { PointArray =
this
.PointArray };
//执行完成动画并触发记忆事件
PlayAnimation(
true
, () =>
{
if
(OnRememberPoint !=
null
)
{
this
.Dispatcher.BeginInvoke(OnRememberPoint,
this
, args);
//触发图形记忆事件
}
});
}
}
}
|
判断线是否经过了附近的某个点 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
/// <summary>
/// 两点计算一线的长度
/// </summary>
/// <param name="pt1"></param>
/// <param name="pt2"></param>
/// <returns></returns>
private
double
GetLineLength(
double
x1,
double
y1,
double
x2,
double
y2)
{
return
Math.Sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
//根据两点计算线段长度公式 √((x1-x2)²x(y1-y2)²)
}
/// <summary>
/// 判断线是否经过了某个点
/// </summary>
/// <param name="ellipse"></param>
/// <returns></returns>
private
Ellipse IsOnLine()
{
double
lineAB = 0;
//当前画线的长度
double
lineCA = 0;
//当前点和A点的距离
double
lineCB = 0;
//当前点和B点的距离
double
dis = 0;
double
deciation = 1;
//允许的偏差距离
lineAB = GetLineLength(currentLine.X1, currentLine.Y1, currentLine.X2, currentLine.Y2);
//计算当前画线的长度
foreach
(Ellipse ellipse
in
ellipseList)
{
if
(currentPointArray.Contains(ellipse.Tag.ToString()))
//排除已经经过的点
continue
;
var ellipseCenterPoint = GetCenterPoint(ellipse);
//取当前点的中心点
lineCA = GetLineLength(currentLine.X1, currentLine.Y1, ellipseCenterPoint.X, ellipseCenterPoint.Y);
//计算当前点到线A端的长度
lineCB = GetLineLength(currentLine.X2, currentLine.Y2, ellipseCenterPoint.X, ellipseCenterPoint.Y);
//计算当前点到线B端的长度
dis = Math.Abs(lineAB - (lineCA + lineCB));
//线CA的长度+线CB的长度>当前线AB的长度 说明点不在线上
if
(dis <= deciation)
//因为绘制的点具有一个宽度和高度,所以需设定一个允许的偏差范围,让线靠近点就命中之(吸附效果)
{
return
ellipse;
}
}
return
null
;
}
|
检查点是否正确,按数组顺序逐个匹配之 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
/// <summary>
/// 检查坐标点是否正确
/// </summary>
/// <returns></returns>
private
bool
CheckPoint()
{
//PointArray:正确的坐标值数组
//currentPointArray:当前绘制的坐标值数组
if
(currentPointArray.Count != PointArray.Count)
return
false
;
for
(var i = 0; i < currentPointArray.Count; i++)
{
if
(currentPointArray[i] != PointArray[i])
return
false
;
}
return
true
;
}
|
记录经过点,并创建一条新的线 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
/// <summary>
/// 记录经过的点
/// </summary>
/// <param name="ellipse"></param>
private
void
OnAfterByPoint(Ellipse ellipse)
{
var ellipseCenterPoint = GetCenterPoint(ellipse);
currentLine.X2 = ellipseCenterPoint.X;
currentLine.Y2 = ellipseCenterPoint.Y;
currentLine = CreateLine();
currentLine.X1 = currentLine.X2 = ellipseCenterPoint.X;
currentLine.Y1 = currentLine.Y2 = ellipseCenterPoint.Y;
currentPointArray.Add(ellipse.Tag.ToString());
Console.WriteLine(
string
.Join(
","
, currentPointArray));
currentLineList.Add(currentLine);
canvasRoot.Children.Add(currentLine);
}
|
1
2
3
4
5
6
7
8
9
10
|
/// <summary>
/// 获取原点的中心点坐标
/// </summary>
/// <param name="ellipse"></param>
/// <returns></returns>
private
Point GetCenterPoint(Ellipse ellipse)
{
Point p =
new
Point(Canvas.GetLeft(ellipse) + ellipse.Width / 2, Canvas.GetTop(ellipse) + ellipse.Height / 2);
return
p;
}
|
当绘制完成时,执行完成动画并触发响应模式的事件 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
/// <summary>
/// 执行动画
/// </summary>
/// <param name="result"></param>
private
void
PlayAnimation(
bool
result, Action callback =
null
)
{
Task.Factory.StartNew(() =>
{
this
.Dispatcher.Invoke((Action)
delegate
{
foreach
(Line l
in
currentLineList)
l.Stroke = result ? rightColor : errorColor;
foreach
(Ellipse e
in
ellipseList)
if
(currentPointArray.Contains(e.Tag.ToString()))
e.Fill = result ? rightColor : errorColor;
});
Thread.Sleep(1500);
this
.Dispatcher.Invoke((Action)
delegate
{
foreach
(Line l
in
currentLineList)
this
.canvasRoot.Children.Remove(l);
foreach
(Ellipse e
in
ellipseList)
e.Fill = Color;
});
currentLine =
null
;
this
.currentPointArray.Clear();
this
.currentLineList.Clear();
isChecking =
false
;
}).ContinueWith(t =>
{
try
{
if
(callback !=
null
)
callback();
}
catch
(Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
t.Dispose();
}
});
}
|
图形解锁的调用 。
1
2
3
4
5
6
7
8
9
10
11
12
|
<local:ScreenUnlock Width=
"500"
Height=
"500"
PointArray=
"{Binding PointArray, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Operation=
"Check"
> <!--或Remember-->
<i:Interaction.Triggers>
<i:EventTrigger EventName=
"OnCheckedPoint"
>
<Custom:EventToCommand Command=
"{Binding OnCheckedPoint}"
PassEventArgsToCommand=
"True"
/>
</i:EventTrigger>
<i:EventTrigger EventName=
"OnRememberPoint"
>
<Custom:EventToCommand Command=
"{Binding OnRememberPoint}"
PassEventArgsToCommand=
"True"
/>
</i:EventTrigger>
</i:Interaction.Triggers>
</local:ScreenUnlock>
|
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我.
最后此篇关于WPF图形解锁控件ScreenUnLock使用详解的文章就讲到这里了,如果你想了解更多关于WPF图形解锁控件ScreenUnLock使用详解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
大家好,我是汤师爷~ 什么是订单履约系统? 订单履约是从消费者下单支付到收到商品的全流程管理过程,包括订单接收、订单派单、库存分配、仓储管理和物流配送等环节,核心目标是确保商品准时、准确地送达消费
大家好,我是汤师爷~ 今天聊聊促销系统整体规划。 各类促销活动的系统流程,可以抽象为3大阶段: B端促销活动管理:商家运营人员在后台系统中配置和管理促销活动,包括设定活动基本信息、使用规则
全称“Java Virtual Machine statistics monitoring tool”(statistics 统计;monitoring 监控;tool 工具) 用于监控虚拟机的各种运
主要是讲下Mongodb的索引的查看、创建、删除、类型说明,还有就是Explain执行计划的解释说明。 可以转载,但请注明出处。  
1>单线程或者单进程 相当于短链接,当accept之后,就开始数据的接收和数据的发送,不接受新的连接,即一个server,一个client 不存在并发。 2>循环服务器和并发服务器
详解 linux中的关机和重启命令 一 shutdown命令 shutdown [选项] 时间 选项: ?
首先,将json串转为一个JObject对象: ? 1
matplotlib官网 matplotlib库默认英文字体 添加黑体(‘SimHei')为绘图字体 代码: plt.rcParams['font.sans-serif']=['SimHei'
在并发编程中,synchronized关键字是常出现的角色。之前我们都称呼synchronized关键字为重量锁,但是在jdk1.6中对synchronized进行了优化,引入了偏向锁、轻量锁。本篇
一般我们的项目中会使用1到2个数据库连接配置,同程艺龙的数据库连接配置被收拢到统一的配置中心,由DBA统一配置和维护,业务方通过某个字符串配置拿到的是Connection对象。  
实例如下: ? 1
1. MemoryCahe NetCore中的缓存和System.Runtime.Caching很相似,但是在功能上做了增强,缓存的key支持object类型;提供了泛型支持;可以读缓存和单个缓存
argument是javascript中函数的一个特殊参数,例如下文,利用argument访问函数参数,判断函数是否执行 复制代码 代码如下: <script
一不小心装了一个Redis服务,开了一个全网的默认端口,一开始以为这台服务器没有公网ip,结果发现之后悔之莫及啊 某天发现cpu load高的出奇,发现一个minerd进程 占了大量cpu,googl
今天写这个是为了 提醒自己 编程过程 不仅要有逻辑 思想 还有要规范 代码 这样可读性 1、PHP 编程规范与编码习惯最主要的有以下几点: 1 文件说明 2 funct
摘要:虚拟机安装时一般都采用最小化安装,默认没有lspci工具。一台测试虚拟网卡性能的虚拟机,需要lspci工具来查看网卡的类型。本文描述了在一个虚拟机中安装lspci工具的具体步骤。 由于要测试
1、修改用户进程可打开文件数限制 在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时,最高的并发数量都要受到系统对用户单一进程同时可打开文件数量的限制(这是因为系统
目录 算术运算符 基本四则运算符 增量赋值运算符 自增/自减运算符 关系运算符 逻
如下所示: ? 1
MapperScannerConfigurer之sqlSessionFactory注入方式讲解 首先,Mybatis中的有一段配置非常方便,省去我们去写DaoImpl(Dao层实现类)的时间,这个
我是一名优秀的程序员,十分优秀!