diff --git a/HandyControl/Controls/Attach/InfoElement.cs b/HandyControl/Controls/Attach/InfoElement.cs index 088aa1f3..96556197 100644 --- a/HandyControl/Controls/Attach/InfoElement.cs +++ b/HandyControl/Controls/Attach/InfoElement.cs @@ -20,7 +20,7 @@ namespace HandyControl.Controls /// 占位符 /// public static readonly DependencyProperty PlaceholderProperty = DependencyProperty.RegisterAttached( - "Placeholder", typeof(string), typeof(InfoElement), new PropertyMetadata(default(string))); + "Placeholder", typeof(string), typeof(InfoElement), new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.Inherits)); public static void SetPlaceholder(DependencyObject element, string value) => element.SetValue(PlaceholderProperty, value); @@ -70,7 +70,7 @@ namespace HandyControl.Controls /// 内容高度 /// public static readonly DependencyProperty ContentHeightProperty = DependencyProperty.RegisterAttached( - "ContentHeight", typeof(double), typeof(InfoElement), new PropertyMetadata(30.0)); + "ContentHeight", typeof(double), typeof(InfoElement), new FrameworkPropertyMetadata(30.0, FrameworkPropertyMetadataOptions.Inherits)); public static void SetContentHeight(DependencyObject element, double value) => element.SetValue(ContentHeightProperty, value); diff --git a/HandyControl/Controls/Attach/PasswordBoxMonitor.cs b/HandyControl/Controls/Attach/PasswordBoxMonitor.cs index 9c469155..0e78d619 100644 --- a/HandyControl/Controls/Attach/PasswordBoxMonitor.cs +++ b/HandyControl/Controls/Attach/PasswordBoxMonitor.cs @@ -1,5 +1,4 @@ using System.Windows; -using System.Windows.Controls; using HandyControl.Data; // ReSharper disable once CheckNamespace @@ -25,7 +24,7 @@ namespace HandyControl.Controls private static void OnIsMonitoringChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - if (d is PasswordBox passwordBox) + if (d is System.Windows.Controls.PasswordBox passwordBox) { if (e.NewValue is bool boolValue) { @@ -47,7 +46,7 @@ namespace HandyControl.Controls private static void PasswordChanged(object sender, RoutedEventArgs e) { - if (sender is PasswordBox passwordBox) + if (sender is System.Windows.Controls.PasswordBox passwordBox) { SetPasswordLength(passwordBox, passwordBox.Password.Length); } diff --git a/HandyControl/Controls/Input/PasswordBox.cs b/HandyControl/Controls/Input/PasswordBox.cs new file mode 100644 index 00000000..22e2168f --- /dev/null +++ b/HandyControl/Controls/Input/PasswordBox.cs @@ -0,0 +1,172 @@ +using System; +using System.ComponentModel; +using System.Security; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using HandyControl.Data; +using HandyControl.Interactivity; +using HandyControl.Properties.Langs; + +namespace HandyControl.Controls +{ + /// + public class PasswordBox : Control, IDataInput + { + private const string ElementPasswordBox = "PART_PasswordBox"; + + /// + /// 掩码字符 + /// + public static readonly DependencyProperty PasswordCharProperty = + System.Windows.Controls.PasswordBox.PasswordCharProperty.AddOwner(typeof(PasswordBox), + new FrameworkPropertyMetadata('●')); + + /// + /// 数据是否错误 + /// + public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register( + "IsError", typeof(bool), typeof(PasswordBox), new PropertyMetadata(default(bool))); + + /// + /// 错误提示 + /// + public static readonly DependencyProperty ErrorStrProperty = DependencyProperty.Register( + "ErrorStr", typeof(string), typeof(PasswordBox), new PropertyMetadata(default(string))); + + /// + /// 文本类型 + /// + public static readonly DependencyProperty TextTypeProperty = DependencyProperty.Register( + "TextType", typeof(TextType), typeof(PasswordBox), new PropertyMetadata(default(TextType))); + + /// + /// 是否显示清除按钮 + /// + public static readonly DependencyProperty ShowClearButtonProperty = DependencyProperty.Register( + "ShowClearButton", typeof(bool), typeof(PasswordBox), new PropertyMetadata(default(bool))); + + private string _password; + + private char _passwordChar; + + public PasswordBox() + { + CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) => ActualPasswordBox.Clear())); + } + + public System.Windows.Controls.PasswordBox ActualPasswordBox { get; set; } + + [DefaultValue("")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string Password + { + get => ActualPasswordBox?.Password; + set + { + if (ActualPasswordBox == null) + { + _password = value; + return; + } + ActualPasswordBox.Password = value; + } + } + + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public SecureString SecurePassword => ActualPasswordBox?.SecurePassword; + + public char PasswordChar + { + get => (char) GetValue(PasswordCharProperty); + set => SetValue(PasswordCharProperty, value); + } + + public Func> VerifyFunc { get; set; } + + public bool IsError + { + get => (bool) GetValue(IsErrorProperty); + set => SetValue(IsErrorProperty, value); + } + + public string ErrorStr + { + get => (string) GetValue(ErrorStrProperty); + set => SetValue(ErrorStrProperty, value); + } + + public TextType TextType + { + get => (TextType) GetValue(TextTypeProperty); + set => SetValue(TextTypeProperty, value); + } + + public bool ShowClearButton + { + get => (bool) GetValue(ShowClearButtonProperty); + set => SetValue(ShowClearButtonProperty, value); + } + + public virtual bool VerifyData() + { + OperationResult result; + + if (VerifyFunc != null) + { + result = VerifyFunc.Invoke(ActualPasswordBox.Password); + } + else + { + if (!string.IsNullOrEmpty(ActualPasswordBox.Password)) + result = OperationResult.Success(); + else if (InfoElement.GetNecessary(this)) + result = OperationResult.Failed(Lang.IsNecessary); + else + result = OperationResult.Success(); + } + + IsError = !result.Data; + ErrorStr = result.Message; + return result.Data; + } + + public override void OnApplyTemplate() + { + if (ActualPasswordBox != null) + ActualPasswordBox.PasswordChanged -= PasswordBox_PasswordChanged; + + base.OnApplyTemplate(); + + ActualPasswordBox = GetTemplateChild(ElementPasswordBox) as System.Windows.Controls.PasswordBox; + if (ActualPasswordBox != null) + { + ActualPasswordBox.PasswordChanged += PasswordBox_PasswordChanged; + + if (!string.IsNullOrEmpty(_password)) + { + ActualPasswordBox.Password = _password; + _password = null; + } + if (_passwordChar != default(char)) + { + ActualPasswordBox.PasswordChar = _passwordChar; + _passwordChar = default(char); + } + } + } + + public void Paste() => ActualPasswordBox.Paste(); + + public void SelectAll() => ActualPasswordBox.SelectAll(); + + public void Clear() => ActualPasswordBox.SelectAll(); + + + + private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e) + { + VerifyData(); + } + } +} \ No newline at end of file diff --git a/HandyControl/Controls/Input/TextBox.cs b/HandyControl/Controls/Input/TextBox.cs index 2216919c..abfc12a3 100644 --- a/HandyControl/Controls/Input/TextBox.cs +++ b/HandyControl/Controls/Input/TextBox.cs @@ -6,7 +6,6 @@ using HandyControl.Data; using HandyControl.Interactivity; using HandyControl.Tools; -// ReSharper disable once CheckNamespace namespace HandyControl.Controls { /// diff --git a/HandyControl/HandyControl.csproj b/HandyControl/HandyControl.csproj index dbdfa326..52f78b16 100644 --- a/HandyControl/HandyControl.csproj +++ b/HandyControl/HandyControl.csproj @@ -54,6 +54,7 @@ + diff --git a/HandyControl/Themes/Styles/Base/PasswordBoxBaseStyle.xaml b/HandyControl/Themes/Styles/Base/PasswordBoxBaseStyle.xaml index 17477ef2..d4148471 100644 --- a/HandyControl/Themes/Styles/Base/PasswordBoxBaseStyle.xaml +++ b/HandyControl/Themes/Styles/Base/PasswordBoxBaseStyle.xaml @@ -1,7 +1,16 @@  + xmlns:controls="clr-namespace:HandyControl.Controls" + xmlns:system="clr-namespace:System;assembly=mscorlib" + xmlns:interactivity="clr-namespace:HandyControl.Interactivity"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +