This article is mainly for you to introduce the WPF graphics unlock control screenunlock use method, with a certain reference value, interested in small partners can refer to
The Screenunlock is the same as the pattern unlock feature on your smartphone. Achieve the purpose of unlocking or remembering graphics by drawing graphics.
I had a whim to port the graphics unlock feature on my phone to WPF. are also applied to the company's projects.
Before creating the Screenunlock, we first analyze the implementation of the one-shape unlocking method.
1. Create nine Gongge origin (or more squares) with each point defining a coordinate value
2. Provide graphics unlock related extended properties and events for easy caller definition. For example: color of dots and lines, operating mode (check| Remember), verify the correct color (rightcolor), validate the failed color (errorcolor), unlock event Oncheckedpoint, memory event onrememberpoint, etc.;
3. Define the MouseMove event listener draw line behavior. The drawing line part is also the core of this paper. In the process of drawing lines. The program needs to determine which point the line is drawn from and what point it passed (excluding the points that have been recorded). Whether you have finished drawing, and so on.
4. Draw the line to finish, according to the mode of operation to handle the line completion behavior. and invoke related custom events
General ideas as above, the following start to write Screenunlock step by step
Create Screenunlock
public partial class Screenunlock:usercontrol
Defining related properties
<summary>///Verify the correct color///</summary> private SolidColorBrush rightcolor; <summary>///validation failed colors///</summary> private SolidColorBrush errorcolor; <summary>///Whether the design is in check///</summary> private bool ischecking; public static readonly DependencyProperty Pointarrayproperty = Dependencyproperty.register ("Pointarray", typeof (IList <string>), typeof (Screenunlock)); <summary>////memory coordinate points///</summary> public ilist<string> Pointarray {get {return GetValue (P Ointarrayproperty) as ilist<string>; } set {SetValue (Pointarrayproperty, value);} }///<summary>///Current coordinate point collection///</summary> private ilist<string> Currentpointarray; <summary>///Current line collection///</summary> private ilist<line> currentlinelist; <summary>///point collection///</summary> private ilist<ellipse> ellipselist; <summary>///The line currently being drawn///</summary> PRivate line CurrentLine; public static readonly DependencyProperty Operationporperty = dependencyproperty.register ("Operation", typeof ( Screenunlockoperationtype), typeof (Screenunlock), New Frameworkpropertymetadata ( Screenunlockoperationtype.remember)); <summary>///operation type///</summary> public screenunlockoperationtype operation {get {return (Screenu Nlockoperationtype) GetValue (Operationporperty); } set {SetValue (Operationporperty, value);} } public static readonly DependencyProperty Pointsizeproperty = Dependencyproperty.register ("Pointsize", typeof (double ), typeof (Screenunlock), new Frameworkpropertymetadata (15.0)); <summary>///coordinate point size///</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 Screenunlo CK). Refresh (); }))); <summary>///coordinate point and Line color////</summary> public SolidColorBrush Color {get {return GetValue (colorprop erty) as SolidColorBrush; } set {SetValue (Colorproperty, value);} }///<summary>///operation type///</summary> public enum Screenunlockoperationtype {Remem ber = 0, Check = 1}
Initialize Screenunlock
Public Screenunlock () { InitializeComponent (); This. Loaded + = screenunlock_loaded; This. Unloaded + = screenunlock_unloaded; This. MouseMove + = Screenunlock_mousemove; Listener Draw event } 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 (); }
Create point
<summary> //Create point///</summary> private void Createpoint () { CanvasRoot.Children.Clear (); int row = 3, column = 3; Three rows of three columns, nine double onecolumnwidth = (this. ActualWidth = = 0? This. Width:this. ActualWidth)/3; Single-column width double onerowheight = (this. ActualHeight = = 0? This. Height:this. ActualHeight)/3; Single column height double leftdistance = (onecolumnwidth-pointsize)/2;//single row left margin double topdistance = (onerowheight-point Size)/2; Single row top margin 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);}}}
Create lines
Private Line Createline () {line line = new Line () { Stroke = Color, strokethickness = 2 }; return line; }
Both point and line creation are defined so that you can start listening for drawing events.
private void Screenunlock_mousemove (object sender, System.Windows.Input.MouseEventArgs e) {if (ischecking)//If the graphic is being examined , does not respond to subsequent processing 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) {//draw from scratch 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 {//encounters the next point, excluding the point if Currentpointarray.contains (ellipse. Tag.tostring ())) return; OnafterbyPoint (Ellipse); }} else if (currentline! = null) {//currentline.x2 = point during drawing. X Currentline.y2 = point. Y Determine if the current line has passed the point ellipse = IsOnLine (); if (ellipse! = null) onafterbypoint (ellipse); }} else {if (Currentpointarray.count = = 0) return; Ischecking = true; if (Currentlinelist.count + 1! = Currentpointarray.count) {//The end of the last line is not at the point//2.1 line, the number of points-1 equals the number of lines of the line Currentlinel Ist. Remove (CurrentLine); Removes the last redundant line CanvasRoot.Children.Remove (CurrentLine) from the recorded line collection; Remove the last extra line from the interface currentline = null; } if (operation = = Screenunlockoperationtype.check) {Console.WriteLine ("Playanimation Check"); var result = CheckPoint (); Performs a graphical check//execution of the completion animation and triggers a check event playanimation (result, () = {if (Oncheckedpoint! = null) { This. Dispatcher.begininvoke (Oncheckedpoint, this, new Checkpointargs () {result = result}); Trigger check Completion event}}); } else if (Operation = = Screenunlockoperationtype.remember) {Console.WriteLine ("Playanimation Remember"); Rememberpoint (); Memory draws the coordinates var args = new Rememberpointargs () {Pointarray = this. Pointarray}; Performs a complete animation and triggers a memory event playanimation (true, () = {if (Onrememberpoint! = null) {this. Dispatcher.begininvoke (Onrememberpoint, this, args); Trigger graphics Memory Event}}); } } }
Determine if a line has passed a nearby point
<summary>///Two-point calculation of the length of the line///</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))///////////////////////////////////////////Two <summary>///Judgment line has passed a certain point///</summary>//<param name= "ellipse" ></param>//<return s></returns> private Ellipse IsOnLine () {double Lineab = 0;//current draw line length double Lineca = 0;//distance between current point and point a Do Uble LINECB = 0; The distance between the current point and point B is double dis = 0; Double deciation = 1; allowable deviation Distance Lineab = getlinelength (currentline.x1, Currentline.y1, currentline.x2, currentline.y2); Calculates the length of the current drawing line foreach (Ellipse Ellipse in ellipselist) {if (Currentpointarray.contains (Ellipse. Tag.tostring ()))//Exclude points continue that have been passed; var ellipsecenterpoint = Getcenterpoint (ellipse); Take the center point of the current point Lineca =Getlinelength (currentline.x1, Currentline.y1, Ellipsecenterpoint.x, ELLIPSECENTERPOINT.Y); Calculates the length of the current point to line a end LINECB = Getlinelength (currentline.x2, Currentline.y2, Ellipsecenterpoint.x, ELLIPSECENTERPOINT.Y); Calculates the length of the current point-to-line B-end dis = Math.Abs (Lineab-(Lineca + LINECB)); Length of line CA + line CB length > Current line AB length description point not on line if (dis <= deciation)///Because the drawn point has a width and height, it is necessary to set an allowable deviation range so that the line is close to the point of the hit (adsorption effect) { return ellipse; }} return null; }
Check points are correct, matching them in array order
<summary>// check coordinate points correctly///</summary>// <returns></returns> Private BOOL CheckPoint () {//pointarray: Correct array of coordinate values//currentpointarray: array of coordinate values currently plotted if (currentpointarray.co Unt! = Pointarray.count) return false; for (var i = 0; i < Currentpointarray.count; i++) { if (currentpointarray[i]! = Pointarray[i]) return Fals e; } return true; }
Record past points and create a new line
<summary>///record past points///</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); }
<summary>/// get the center point coordinates of the origin///</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; }
When the drawing is complete, an event that finishes the animation and triggers the response mode is executed
<summary>///Animation///</summary>/<param name= "result" ></param> private void Playanima tion (bool result, Action callback = null) {Task.Factory.StartNew () = {this. Dispatcher.invoke (Action) delegate {foreach (line L in currentlinelist) L.stroke = result? Rightcolor:erro Rcolor; 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 (); } }); }
Call to unlock Graphics
<local:screenunlock width= "height=" " pointarray=" {Binding Pointarray, Mode=twoway, updatesourcetrigger=propertychanged} " operation=" Check "> <!--or 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>