Explain how to unlock controls with WPF graphics Screenunlock

Source: Internet
Author: User
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>
  /// color of validation failure
  /// </ summary>
  private SolidColorBrush errorColor;

  /// <summary>
  /// Whether the pattern is being checked
  /// </ summary>
  private bool isChecking;

  public static readonly DependencyProperty PointArrayProperty = DependencyProperty.Register ("PointArray", typeof (IList <string>), typeof (ScreenUnlock));
  /// <summary>
  /// memorized coordinate points
  /// </ summary>
  public IList <string> PointArray
  {
   get {return GetValue (PointArrayProperty) as IList <string>;}
   set {SetValue (PointArrayProperty, value);}
  }

  /// <summary>
  /// current coordinate point set
  /// </ 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 (ScreenUnLockOperationType) 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 ScreenUnlock) .Refresh ();
  })));

  /// <summary>
  /// coordinate point and line color
  /// </ summary>
  public SolidColorBrush Color
  {
   get {return GetValue (ColorProperty) as SolidColorBrush;}
   set {SetValue (ColorProperty, value);}
  }

 /// <summary>
 /// operation type
 /// </ summary>
 Public enum ScreenUnLockOperationType
 {
  Remember = 0, Check = 1
 }


Initialize Screenunlock





public ScreenUnlock ()
   {
    InitializeComponent ();
    this.Loaded + = ScreenUnlock_Loaded;
    this.Unloaded + = ScreenUnlock_Unloaded;
    this.MouseMove + = ScreenUnlock_MouseMove; // Listen to draw events
   }
  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 points
   /// </ summary>
   private void CreatePoint ()
   {
    canvasRoot.Children.Clear ();
    int row = 3, column = 3; // Three rows and three columns, Jiugongge
    double oneColumnWidth = (this.ActualWidth == 0? this.Width: this.ActualWidth) / 3; // The width of a single column
    double oneRowHeight = (this.ActualHeight == 0? this.Height: this.ActualHeight) / 3; // Height of a single column
    double leftDistance = (oneColumnWidth-PointSize) / 2; // Single column left margin
    double topDistance = (oneRowHeight-PointSize) / 2; // Single column 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 graphics are being checked, do 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
     {
      // Meet the next point, exclude points that have passed
      if (currentPointArray.Contains (ellipse.Tag.ToString ()))
       return;
      OnAfterByPoint (ellipse);
     }
    }
    else if (currentLine! = null)
    {
     // During the drawing process
     currentLine.X2 = point.X;
     currentLine.Y2 = point.Y;

     // Judge whether the current Line passes through 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 on the point
     // Two points and one line, the number of points -1 is equal to the number of lines
     currentLineList.Remove (currentLine); // Remove the last extra line from the set of recorded lines
     canvasRoot.Children.Remove (currentLine); // Remove the last extra line from the interface
     currentLine = null;
    }

    if (Operation == ScreenUnLockOperationType.Check)
    {
     Console.WriteLine ("playAnimation Check");
     var result = CheckPoint (); // Perform graphic check
// Execute completion animation and trigger 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 (); // Remember drawing coordinates
     var args = new RememberPointArgs () {PointArray = this.PointArray};
// Execute completion animation and trigger memory events
     PlayAnimation (true, () =>
     {
      if (OnRememberPoint! = null)
      {
       this.Dispatcher.BeginInvoke (OnRememberPoint, this, args); // Trigger the graphic memory event
      }
     });
    }
   }
  }


Determine if a line has passed a nearby point





/// <summary>
  /// calculate the length of a line at two points
  /// </ 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)); // Calculate the line length formula based on two points√ ((x1-x2) ²x (y1- y2) ²)
  }

  /// <summary>
  /// determine whether the line has passed a certain point
  /// </ summary>
  /// <param name = "ellipse"> </ param>
  /// <returns> </ returns>
  private Ellipse IsOnLine ()
  {
   double lineAB = 0; // length of the current line
   double lineCA = 0; // distance between current point and point A
   double lineCB = 0; // distance between current point and point B
   double dis = 0;
   double deciation = 1; // allowable deviation distance
   lineAB = GetLineLength (currentLine.X1, currentLine.Y1, currentLine.X2, currentLine.Y2); // Calculate the length of the currently drawn line

   foreach (Ellipse ellipse in ellipseList)
   {
    if (currentPointArray.Contains (ellipse.Tag.ToString ())) // Exclude points that have passed
     continue;
    var ellipseCenterPoint = GetCenterPoint (ellipse); // Get the center point of the current point
    lineCA = GetLineLength (currentLine.X1, currentLine.Y1, ellipseCenterPoint.X, ellipseCenterPoint.Y); // Calculate the length from the current point to the A end of the line
    lineCB = GetLineLength (currentLine.X2, currentLine.Y2, ellipseCenterPoint.X, ellipseCenterPoint.Y); // Calculate the length from the current point to the B end of the line
    dis = Math.Abs (lineAB-(lineCA + lineCB)); // length of line CA + length of line CB> length of current line AB
    if (dis <= deciation) // Because the drawn point has a width and height, you need to set an allowable deviation range, and let the line hit the point and hit it (adsorption effect)
    {
     return ellipse;
    }
   }
   return null;
  }


Check points are correct, matching them in array order





/// <summary>
   /// check if the coordinate points are correct
   /// </ summary>
   /// <returns> </ returns>
   private bool CheckPoint ()
   {
/// PointArray: the correct array of coordinate values
  Current // currentPointArray: array of coordinate values currently drawn
    if (currentPointArray.Count! = PointArray.Count)
     return false;
    for (var i = 0; i <currentPointArray.Count; i ++)
    {
     if (currentPointArray [i]! = PointArray [i])
      return false;
    }
    return true;
   }


Record past points and create a new line





/// <summary>
   /// record the points passed
   /// </ 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 coordinates of the center point 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>
  /// execute the animation
  /// </ 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 ();
    }
   });
  }


Call to unlock Graphics





<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>




Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.