completed the branch
This commit is contained in:
1 parent
958cda81a7
commit
e2f24256f6
7 files changed
+153
-20
No files matched your search
@@ -94,6 +94,10 @@ Step 4:enjoy coding
|
|||||||
|
|
||||||
## Latest examples
|
## Latest examples
|
||||||
|
|
||||||
|
### PinBox
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
### Effects
|
### Effects
|
||||||
|
|
||||||

|

|
||||||
@@ -110,12 +114,12 @@ Step 4:enjoy coding
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
## History publication
|
||||||
|
|
||||||
### Divider
|
### Divider
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## History publication
|
|
||||||
|
|
||||||
### GeometryAnimation
|
### GeometryAnimation
|
||||||
|
|
||||||

|

|
||||||
|
|||||||
@@ -13,8 +13,7 @@
|
|||||||
<hc:PasswordBox ShowEyeButton="True" hc:InfoElement.Placeholder="{x:Static langs:Lang.PlsEnterContent}" hc:InfoElement.Title="{x:Static langs:Lang.TitleDemoStr2}" hc:InfoElement.Necessary="True" Margin="0,32,0,0"/>
|
<hc:PasswordBox ShowEyeButton="True" hc:InfoElement.Placeholder="{x:Static langs:Lang.PlsEnterContent}" hc:InfoElement.Title="{x:Static langs:Lang.TitleDemoStr2}" hc:InfoElement.Necessary="True" Margin="0,32,0,0"/>
|
||||||
|
|
||||||
<hc:PasswordBox ShowClearButton="True" Width="380" hc:InfoElement.TitleWidth="140" hc:InfoElement.TitleAlignment="Left" hc:InfoElement.Title="{x:Static langs:Lang.TitleDemoStr3}" Margin="0,32,0,0" Password="123456"/>
|
<hc:PasswordBox ShowClearButton="True" Width="380" hc:InfoElement.TitleWidth="140" hc:InfoElement.TitleAlignment="Left" hc:InfoElement.Title="{x:Static langs:Lang.TitleDemoStr3}" Margin="0,32,0,0" Password="123456"/>
|
||||||
<!--<hc:PasswordBox ShowClearButton="True" ShowEyeButton="True" Width="380" hc:InfoElement.TitleWidth="140" hc:InfoElement.Placeholder="{x:Static langs:Lang.PlsEnterContent}" hc:InfoElement.TitleAlignment="Left" hc:InfoElement.Title="{x:Static langs:Lang.TitleDemoStr3}" hc:InfoElement.Necessary="True" Margin="0,32,0,0"/>-->
|
<hc:PasswordBox ShowClearButton="True" ShowEyeButton="True" Width="380" hc:InfoElement.TitleWidth="140" hc:InfoElement.Placeholder="{x:Static langs:Lang.PlsEnterContent}" hc:InfoElement.TitleAlignment="Left" hc:InfoElement.Title="{x:Static langs:Lang.TitleDemoStr3}" hc:InfoElement.Necessary="True" Margin="0,32,0,0"/>
|
||||||
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</hc:TransitioningContentControl>
|
</hc:TransitioningContentControl>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@@ -4,6 +4,9 @@
|
|||||||
xmlns:hc="https://handyorg.github.io/handycontrol"
|
xmlns:hc="https://handyorg.github.io/handycontrol"
|
||||||
Background="{DynamicResource RegionBrush}">
|
Background="{DynamicResource RegionBrush}">
|
||||||
<hc:TransitioningContentControl>
|
<hc:TransitioningContentControl>
|
||||||
<hc:PinBox Length="6"/>
|
<StackPanel Margin="32" VerticalAlignment="Center" hc:PinBox.Completed="PinBox_OnCompleted">
|
||||||
|
<hc:PinBox Length="4" Password="1234"/>
|
||||||
|
<hc:PinBox Length="6" Password="123456" Margin="0,16,0,0" PasswordChar="❤"/>
|
||||||
|
</StackPanel>
|
||||||
</hc:TransitioningContentControl>
|
</hc:TransitioningContentControl>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
namespace HandyControlDemo.UserControl
|
using System.Windows;
|
||||||
|
using HandyControl.Controls;
|
||||||
|
|
||||||
|
namespace HandyControlDemo.UserControl
|
||||||
{
|
{
|
||||||
public partial class PinBoxDemoCtl
|
public partial class PinBoxDemoCtl
|
||||||
{
|
{
|
||||||
@@ -6,5 +9,13 @@
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void PinBox_OnCompleted(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.OriginalSource is PinBox pinBox)
|
||||||
|
{
|
||||||
|
Growl.Info(pinBox.Password);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,8 +60,6 @@ namespace HandyControl.Controls
|
|||||||
|
|
||||||
private SecureString _password;
|
private SecureString _password;
|
||||||
|
|
||||||
private char _passwordChar;
|
|
||||||
|
|
||||||
private System.Windows.Controls.TextBox _textBox;
|
private System.Windows.Controls.TextBox _textBox;
|
||||||
|
|
||||||
public PasswordBox()
|
public PasswordBox()
|
||||||
@@ -223,12 +221,6 @@ namespace HandyControl.Controls
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_passwordChar != default(char))
|
|
||||||
{
|
|
||||||
ActualPasswordBox.PasswordChar = _passwordChar;
|
|
||||||
_passwordChar = default;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_textBox != null)
|
if (_textBox != null)
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Security;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using HandyControl.Data;
|
using HandyControl.Data;
|
||||||
using HandyControl.Tools;
|
using HandyControl.Tools;
|
||||||
|
using HandyControl.Tools.Extension;
|
||||||
|
|
||||||
namespace HandyControl.Controls
|
namespace HandyControl.Controls
|
||||||
{
|
{
|
||||||
@@ -21,6 +25,10 @@ namespace HandyControl.Controls
|
|||||||
|
|
||||||
private bool _changed;
|
private bool _changed;
|
||||||
|
|
||||||
|
private bool _isInternalAction;
|
||||||
|
|
||||||
|
private List<SecureString> _passwordList;
|
||||||
|
|
||||||
private RoutedEventHandler _passwordBoxsGotFocusEventHandler;
|
private RoutedEventHandler _passwordBoxsGotFocusEventHandler;
|
||||||
|
|
||||||
private RoutedEventHandler _passwordBoxsPasswordChangedEventHandler;
|
private RoutedEventHandler _passwordBoxsPasswordChangedEventHandler;
|
||||||
@@ -51,6 +59,8 @@ namespace HandyControl.Controls
|
|||||||
|
|
||||||
private void PasswordBoxsPasswordChanged(object sender, RoutedEventArgs e)
|
private void PasswordBoxsPasswordChanged(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
if (_isInternalAction) return;
|
||||||
|
|
||||||
if (e.OriginalSource is System.Windows.Controls.PasswordBox passwordBox)
|
if (e.OriginalSource is System.Windows.Controls.PasswordBox passwordBox)
|
||||||
{
|
{
|
||||||
if (passwordBox.Password.Length > 0)
|
if (passwordBox.Password.Length > 0)
|
||||||
@@ -88,6 +98,7 @@ namespace HandyControl.Controls
|
|||||||
if (e.OriginalSource is System.Windows.Controls.PasswordBox passwordBox)
|
if (e.OriginalSource is System.Windows.Controls.PasswordBox passwordBox)
|
||||||
{
|
{
|
||||||
_inputIndex = _panel.Children.IndexOf(passwordBox);
|
_inputIndex = _panel.Children.IndexOf(passwordBox);
|
||||||
|
passwordBox.SelectAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +114,10 @@ namespace HandyControl.Controls
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FocusManager.SetFocusedElement(this, _panel.Children[_inputIndex]);
|
var passwordBox = _panel.Children[_inputIndex] as System.Windows.Controls.PasswordBox;
|
||||||
|
passwordBox?.SelectAll();
|
||||||
|
|
||||||
|
FocusManager.SetFocusedElement(this, passwordBox);
|
||||||
}
|
}
|
||||||
else if (e.Key == Key.Right)
|
else if (e.Key == Key.Right)
|
||||||
{
|
{
|
||||||
@@ -113,7 +127,10 @@ namespace HandyControl.Controls
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FocusManager.SetFocusedElement(this, _panel.Children[_inputIndex]);
|
var passwordBox = _panel.Children[_inputIndex] as System.Windows.Controls.PasswordBox;
|
||||||
|
passwordBox?.SelectAll();
|
||||||
|
|
||||||
|
FocusManager.SetFocusedElement(this, passwordBox);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,6 +146,13 @@ namespace HandyControl.Controls
|
|||||||
|
|
||||||
if (e.Key == Key.Delete || e.Key == Key.Back)
|
if (e.Key == Key.Delete || e.Key == Key.Back)
|
||||||
{
|
{
|
||||||
|
if (_panel.Children[_inputIndex] is System.Windows.Controls.PasswordBox passwordBox)
|
||||||
|
{
|
||||||
|
_isInternalAction = true;
|
||||||
|
passwordBox.Clear();
|
||||||
|
_isInternalAction = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (--_inputIndex < 0)
|
if (--_inputIndex < 0)
|
||||||
{
|
{
|
||||||
_inputIndex = 0;
|
_inputIndex = 0;
|
||||||
@@ -139,8 +163,66 @@ namespace HandyControl.Controls
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string Password
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return string.Join("", _panel.Children.OfType<System.Windows.Controls.PasswordBox>().Select(item => item.Password));
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_panel == null)
|
||||||
|
{
|
||||||
|
_passwordList = new List<SecureString>();
|
||||||
|
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
value = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in value)
|
||||||
|
{
|
||||||
|
var secureString = new SecureString();
|
||||||
|
secureString.AppendChar(item);
|
||||||
|
_passwordList.Add(secureString);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var length = Length;
|
||||||
|
if (string.IsNullOrEmpty(value) || value.Length != length || value.Length != _panel.Children.Count)
|
||||||
|
{
|
||||||
|
_panel.Children.OfType<System.Windows.Controls.PasswordBox>().Do(item => item.Clear());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_panel.Children.OfType<System.Windows.Controls.PasswordBox>().DoWithIndex((item, index) => item.Password = value[index].ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 掩码字符
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty PasswordCharProperty =
|
||||||
|
System.Windows.Controls.PasswordBox.PasswordCharProperty.AddOwner(typeof(PinBox),
|
||||||
|
new FrameworkPropertyMetadata('●'));
|
||||||
|
|
||||||
|
public char PasswordChar
|
||||||
|
{
|
||||||
|
get => (char)GetValue(PasswordCharProperty);
|
||||||
|
set => SetValue(PasswordCharProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
public static readonly DependencyProperty LengthProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty LengthProperty = DependencyProperty.Register(
|
||||||
"Length", typeof(int), typeof(PinBox), new PropertyMetadata(MinLength, null, CoerceLength), ValidateHelper.IsInRangeOfPosInt);
|
"Length", typeof(int), typeof(PinBox), new PropertyMetadata(MinLength, OnLengthChanged, CoerceLength), ValidateHelper.IsInRangeOfPosInt);
|
||||||
|
|
||||||
|
private static void OnLengthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var ctl = (PinBox) d;
|
||||||
|
ctl.UpdateItems();
|
||||||
|
}
|
||||||
|
|
||||||
private static object CoerceLength(DependencyObject d, object basevalue) => (int)basevalue < 4 ? MinLength : basevalue;
|
private static object CoerceLength(DependencyObject d, object basevalue) => (int)basevalue < 4 ? MinLength : basevalue;
|
||||||
|
|
||||||
@@ -179,9 +261,9 @@ namespace HandyControl.Controls
|
|||||||
|
|
||||||
public static readonly RoutedEvent CompletedEvent =
|
public static readonly RoutedEvent CompletedEvent =
|
||||||
EventManager.RegisterRoutedEvent("Completed", RoutingStrategy.Bubble,
|
EventManager.RegisterRoutedEvent("Completed", RoutingStrategy.Bubble,
|
||||||
typeof(EventHandler), typeof(PinBox));
|
typeof(RoutedEventHandler), typeof(PinBox));
|
||||||
|
|
||||||
public event EventHandler Completed
|
public event RoutedEventHandler Completed
|
||||||
{
|
{
|
||||||
add => AddHandler(CompletedEvent, value);
|
add => AddHandler(CompletedEvent, value);
|
||||||
remove => RemoveHandler(CompletedEvent, value);
|
remove => RemoveHandler(CompletedEvent, value);
|
||||||
@@ -189,6 +271,8 @@ namespace HandyControl.Controls
|
|||||||
|
|
||||||
private void UpdateItems()
|
private void UpdateItems()
|
||||||
{
|
{
|
||||||
|
if (_panel == null) return;
|
||||||
|
|
||||||
_panel.Children.Clear();
|
_panel.Children.Clear();
|
||||||
var length = Length;
|
var length = Length;
|
||||||
|
|
||||||
@@ -208,7 +292,8 @@ namespace HandyControl.Controls
|
|||||||
Margin = ItemMargin,
|
Margin = ItemMargin,
|
||||||
Width = ItemWidth,
|
Width = ItemWidth,
|
||||||
Height = ItemHeight,
|
Height = ItemHeight,
|
||||||
Padding = new Thickness()
|
Padding = default,
|
||||||
|
PasswordChar = PasswordChar
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,6 +305,34 @@ namespace HandyControl.Controls
|
|||||||
if (_panel != null)
|
if (_panel != null)
|
||||||
{
|
{
|
||||||
UpdateItems();
|
UpdateItems();
|
||||||
|
|
||||||
|
var length = Length;
|
||||||
|
if (_passwordList != null && _passwordList.Count == length && _panel.Children.Count == length)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
var password = _passwordList[i];
|
||||||
|
if (password.Length > 0)
|
||||||
|
{
|
||||||
|
var valuePtr = IntPtr.Zero;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
valuePtr = Marshal.SecureStringToGlobalAllocUnicode(password);
|
||||||
|
if (_panel.Children[i] is System.Windows.Controls.PasswordBox passwordBox)
|
||||||
|
{
|
||||||
|
passwordBox.Password = Marshal.PtrToStringUni(valuePtr) ?? throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
|
||||||
|
password.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_passwordList.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,5 +16,16 @@ namespace HandyControl.Tools.Extension
|
|||||||
|
|
||||||
return enumerable;
|
return enumerable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<TSource> DoWithIndex<TSource>(this IEnumerable<TSource> source, Action<TSource, int> predicate)
|
||||||
|
{
|
||||||
|
var enumerable = source as IList<TSource> ?? source.ToList();
|
||||||
|
for (var i = 0; i < enumerable.Count; i++)
|
||||||
|
{
|
||||||
|
predicate.Invoke(enumerable[i], i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return enumerable;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user