Merge branch 'master' into patch-2
This commit is contained in:
986 files changed
+63640
-61515
No files matched your search
+117
-118
@@ -4,156 +4,155 @@ using System.Windows.Input;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Tools.Helper;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
[TemplatePart(Name = SearchTextBox, Type = typeof(System.Windows.Controls.TextBox))]
|
||||
public class AutoCompleteTextBox : ComboBox
|
||||
{
|
||||
[TemplatePart(Name = SearchTextBox, Type = typeof(System.Windows.Controls.TextBox))]
|
||||
public class AutoCompleteTextBox : ComboBox
|
||||
private const string SearchTextBox = "PART_SearchTextBox";
|
||||
|
||||
private bool ignoreTextChanging;
|
||||
|
||||
private System.Windows.Controls.TextBox _searchTextBox;
|
||||
|
||||
private object _selectedItem;
|
||||
|
||||
static AutoCompleteTextBox()
|
||||
{
|
||||
private const string SearchTextBox = "PART_SearchTextBox";
|
||||
TextProperty.OverrideMetadata(typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
|
||||
}
|
||||
|
||||
private bool ignoreTextChanging;
|
||||
|
||||
private System.Windows.Controls.TextBox _searchTextBox;
|
||||
|
||||
private object _selectedItem;
|
||||
|
||||
static AutoCompleteTextBox()
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
if (_searchTextBox != null)
|
||||
{
|
||||
TextProperty.OverrideMetadata(typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
|
||||
_searchTextBox.GotFocus -= SearchTextBoxGotFocus;
|
||||
_searchTextBox.KeyDown -= SearchTextBoxKeyDown;
|
||||
_searchTextBox.TextChanged -= SearchTextBoxTextChanged;
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_searchTextBox = GetTemplateChild(SearchTextBox) as System.Windows.Controls.TextBox;
|
||||
if (_searchTextBox != null)
|
||||
{
|
||||
if (_searchTextBox != null)
|
||||
{
|
||||
_searchTextBox.GotFocus -= SearchTextBoxGotFocus;
|
||||
_searchTextBox.KeyDown -= SearchTextBoxKeyDown;
|
||||
_searchTextBox.TextChanged -= SearchTextBoxTextChanged;
|
||||
}
|
||||
_searchTextBox.GotFocus += SearchTextBoxGotFocus;
|
||||
_searchTextBox.PreviewKeyDown += SearchTextBoxKeyDown;
|
||||
_searchTextBox.TextChanged += SearchTextBoxTextChanged;
|
||||
}
|
||||
|
||||
base.OnApplyTemplate();
|
||||
UpdateTextBoxBySelectedItem(_selectedItem);
|
||||
}
|
||||
|
||||
_searchTextBox = GetTemplateChild(SearchTextBox) as System.Windows.Controls.TextBox;
|
||||
if (_searchTextBox != null)
|
||||
{
|
||||
_searchTextBox.GotFocus += SearchTextBoxGotFocus;
|
||||
_searchTextBox.PreviewKeyDown += SearchTextBoxKeyDown;
|
||||
_searchTextBox.TextChanged += SearchTextBoxTextChanged;
|
||||
}
|
||||
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
|
||||
{
|
||||
base.OnSelectionChanged(e);
|
||||
|
||||
if (e.AddedItems.Count > 0)
|
||||
{
|
||||
_selectedItem = e.AddedItems[0];
|
||||
UpdateTextBoxBySelectedItem(_selectedItem);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
|
||||
protected override bool IsItemItsOwnContainerOverride(object item) => item is AutoCompleteTextBoxItem;
|
||||
|
||||
protected override DependencyObject GetContainerForItemOverride() => new AutoCompleteTextBoxItem();
|
||||
|
||||
private void SearchTextBoxTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
_selectedItem = null;
|
||||
SelectedIndex = -1;
|
||||
|
||||
if (ignoreTextChanging)
|
||||
{
|
||||
base.OnSelectionChanged(e);
|
||||
|
||||
if (e.AddedItems.Count > 0)
|
||||
{
|
||||
_selectedItem = e.AddedItems[0];
|
||||
UpdateTextBoxBySelectedItem(_selectedItem);
|
||||
}
|
||||
ignoreTextChanging = false;
|
||||
return;
|
||||
}
|
||||
|
||||
protected override bool IsItemItsOwnContainerOverride(object item) => item is AutoCompleteTextBoxItem;
|
||||
|
||||
protected override DependencyObject GetContainerForItemOverride() => new AutoCompleteTextBoxItem();
|
||||
|
||||
private void SearchTextBoxTextChanged(object sender, TextChangedEventArgs e)
|
||||
Text = _searchTextBox.Text;
|
||||
if (string.IsNullOrEmpty(Text))
|
||||
{
|
||||
_selectedItem = null;
|
||||
SelectedIndex = -1;
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.FalseBox);
|
||||
_searchTextBox.Focus();
|
||||
}
|
||||
else if (_searchTextBox.IsFocused)
|
||||
{
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.TrueBox);
|
||||
}
|
||||
}
|
||||
|
||||
if (ignoreTextChanging)
|
||||
private void SearchTextBoxKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Up)
|
||||
{
|
||||
var index = SelectedIndex - 1;
|
||||
if (index < 0)
|
||||
{
|
||||
ignoreTextChanging = false;
|
||||
return;
|
||||
index = Items.Count - 1;
|
||||
}
|
||||
|
||||
Text = _searchTextBox.Text;
|
||||
if (string.IsNullOrEmpty(Text))
|
||||
UpdateTextBoxBySelectedIndex(index);
|
||||
}
|
||||
else if (e.Key == Key.Down)
|
||||
{
|
||||
var index = SelectedIndex + 1;
|
||||
if (index >= Items.Count)
|
||||
{
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.FalseBox);
|
||||
_searchTextBox.Focus();
|
||||
}
|
||||
else if (_searchTextBox.IsFocused)
|
||||
{
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.TrueBox);
|
||||
index = 0;
|
||||
}
|
||||
|
||||
UpdateTextBoxBySelectedIndex(index);
|
||||
}
|
||||
else if (e.Key == Key.Enter)
|
||||
{
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.FalseBox);
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTextBoxBySelectedIndex(int selectedIndex)
|
||||
{
|
||||
if (_searchTextBox == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
private void SearchTextBoxKeyDown(object sender, KeyEventArgs e)
|
||||
ignoreTextChanging = true;
|
||||
|
||||
if (ItemContainerGenerator.ContainerFromIndex(selectedIndex) is AutoCompleteTextBoxItem boxItem)
|
||||
{
|
||||
if (e.Key == Key.Up)
|
||||
{
|
||||
var index = SelectedIndex - 1;
|
||||
if (index < 0)
|
||||
{
|
||||
index = Items.Count - 1;
|
||||
}
|
||||
|
||||
UpdateTextBoxBySelectedIndex(index);
|
||||
}
|
||||
else if (e.Key == Key.Down)
|
||||
{
|
||||
var index = SelectedIndex + 1;
|
||||
if (index >= Items.Count)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
|
||||
UpdateTextBoxBySelectedIndex(index);
|
||||
}
|
||||
else if (e.Key == Key.Enter)
|
||||
{
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.FalseBox);
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTextBoxBySelectedIndex(int selectedIndex)
|
||||
{
|
||||
if (_searchTextBox == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ignoreTextChanging = true;
|
||||
|
||||
if (ItemContainerGenerator.ContainerFromIndex(selectedIndex) is AutoCompleteTextBoxItem boxItem)
|
||||
{
|
||||
_searchTextBox.Text = BindingHelper.GetString(boxItem.Content, DisplayMemberPath);
|
||||
_searchTextBox.CaretIndex = _searchTextBox.Text.Length;
|
||||
|
||||
SelectedIndex = selectedIndex;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTextBoxBySelectedItem(object selectedItem)
|
||||
{
|
||||
if (_searchTextBox == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ignoreTextChanging = true;
|
||||
|
||||
_searchTextBox.Text = BindingHelper.GetString(selectedItem, DisplayMemberPath);
|
||||
_searchTextBox.Text = BindingHelper.GetString(boxItem.Content, DisplayMemberPath);
|
||||
_searchTextBox.CaretIndex = _searchTextBox.Text.Length;
|
||||
|
||||
ignoreTextChanging = true;
|
||||
SelectedIndex = selectedIndex;
|
||||
}
|
||||
}
|
||||
|
||||
Text = _searchTextBox.Text;
|
||||
|
||||
ignoreTextChanging = false;
|
||||
private void UpdateTextBoxBySelectedItem(object selectedItem)
|
||||
{
|
||||
if (_searchTextBox == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
private void SearchTextBoxGotFocus(object sender, RoutedEventArgs e)
|
||||
ignoreTextChanging = true;
|
||||
|
||||
_searchTextBox.Text = BindingHelper.GetString(selectedItem, DisplayMemberPath);
|
||||
_searchTextBox.CaretIndex = _searchTextBox.Text.Length;
|
||||
|
||||
ignoreTextChanging = true;
|
||||
|
||||
Text = _searchTextBox.Text;
|
||||
|
||||
ignoreTextChanging = false;
|
||||
}
|
||||
|
||||
private void SearchTextBoxGotFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.TrueBox);
|
||||
}
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.TrueBox);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-4
@@ -1,9 +1,8 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class AutoCompleteTextBoxItem : ComboBoxItem
|
||||
{
|
||||
public class AutoCompleteTextBoxItem : ComboBoxItem
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -9,284 +9,283 @@ using System.Windows.Threading;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Interactivity;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
[TemplatePart(Name = ElementPanel, Type = typeof(Panel))]
|
||||
[TemplatePart(Name = ElementSelectAll, Type = typeof(CheckComboBoxItem))]
|
||||
public class CheckComboBox : ListBox, IDataInput
|
||||
{
|
||||
[TemplatePart(Name = ElementPanel, Type = typeof(Panel))]
|
||||
[TemplatePart(Name = ElementSelectAll, Type = typeof(CheckComboBoxItem))]
|
||||
public class CheckComboBox : ListBox, IDataInput
|
||||
private const string ElementPanel = "PART_Panel";
|
||||
|
||||
private const string ElementSelectAll = "PART_SelectAll";
|
||||
|
||||
private Panel _panel;
|
||||
|
||||
private CheckComboBoxItem _selectAllItem;
|
||||
|
||||
private bool _isInternalAction;
|
||||
|
||||
public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register(
|
||||
"IsError", typeof(bool), typeof(CheckComboBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool IsError
|
||||
{
|
||||
private const string ElementPanel = "PART_Panel";
|
||||
get => (bool) GetValue(IsErrorProperty);
|
||||
set => SetValue(IsErrorProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
private const string ElementSelectAll = "PART_SelectAll";
|
||||
public static readonly DependencyProperty ErrorStrProperty = DependencyProperty.Register(
|
||||
"ErrorStr", typeof(string), typeof(CheckComboBox), new PropertyMetadata(default(string)));
|
||||
|
||||
private Panel _panel;
|
||||
public string ErrorStr
|
||||
{
|
||||
get => (string) GetValue(ErrorStrProperty);
|
||||
set => SetValue(ErrorStrProperty, value);
|
||||
}
|
||||
|
||||
private CheckComboBoxItem _selectAllItem;
|
||||
public static readonly DependencyProperty TextTypeProperty = DependencyProperty.Register(
|
||||
"TextType", typeof(TextType), typeof(CheckComboBox), new PropertyMetadata(default(TextType)));
|
||||
|
||||
private bool _isInternalAction;
|
||||
public TextType TextType
|
||||
{
|
||||
get => (TextType) GetValue(TextTypeProperty);
|
||||
set => SetValue(TextTypeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register(
|
||||
"IsError", typeof(bool), typeof(CheckComboBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
public static readonly DependencyProperty ShowClearButtonProperty = DependencyProperty.Register(
|
||||
"ShowClearButton", typeof(bool), typeof(CheckComboBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool IsError
|
||||
public bool ShowClearButton
|
||||
{
|
||||
get => (bool) GetValue(ShowClearButtonProperty);
|
||||
set => SetValue(ShowClearButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MaxDropDownHeightProperty =
|
||||
System.Windows.Controls.ComboBox.MaxDropDownHeightProperty.AddOwner(typeof(CheckComboBox),
|
||||
new FrameworkPropertyMetadata(SystemParameters.PrimaryScreenHeight / 3));
|
||||
|
||||
[Bindable(true), Category("Layout")]
|
||||
[TypeConverter(typeof(LengthConverter))]
|
||||
public double MaxDropDownHeight
|
||||
{
|
||||
get => (double) GetValue(MaxDropDownHeightProperty);
|
||||
set => SetValue(MaxDropDownHeightProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsDropDownOpenProperty = DependencyProperty.Register(
|
||||
"IsDropDownOpen", typeof(bool), typeof(CheckComboBox), new PropertyMetadata(ValueBoxes.FalseBox, OnIsDropDownOpenChanged));
|
||||
|
||||
private static void OnIsDropDownOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (CheckComboBox) d;
|
||||
|
||||
if (!(bool) e.NewValue)
|
||||
{
|
||||
get => (bool) GetValue(IsErrorProperty);
|
||||
set => SetValue(IsErrorProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ErrorStrProperty = DependencyProperty.Register(
|
||||
"ErrorStr", typeof(string), typeof(CheckComboBox), new PropertyMetadata(default(string)));
|
||||
|
||||
public string ErrorStr
|
||||
{
|
||||
get => (string) GetValue(ErrorStrProperty);
|
||||
set => SetValue(ErrorStrProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextTypeProperty = DependencyProperty.Register(
|
||||
"TextType", typeof(TextType), typeof(CheckComboBox), new PropertyMetadata(default(TextType)));
|
||||
|
||||
public TextType TextType
|
||||
{
|
||||
get => (TextType) GetValue(TextTypeProperty);
|
||||
set => SetValue(TextTypeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowClearButtonProperty = DependencyProperty.Register(
|
||||
"ShowClearButton", typeof(bool), typeof(CheckComboBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool ShowClearButton
|
||||
{
|
||||
get => (bool) GetValue(ShowClearButtonProperty);
|
||||
set => SetValue(ShowClearButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MaxDropDownHeightProperty =
|
||||
System.Windows.Controls.ComboBox.MaxDropDownHeightProperty.AddOwner(typeof(CheckComboBox),
|
||||
new FrameworkPropertyMetadata(SystemParameters.PrimaryScreenHeight / 3));
|
||||
|
||||
[Bindable(true), Category("Layout")]
|
||||
[TypeConverter(typeof(LengthConverter))]
|
||||
public double MaxDropDownHeight
|
||||
{
|
||||
get => (double) GetValue(MaxDropDownHeightProperty);
|
||||
set => SetValue(MaxDropDownHeightProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsDropDownOpenProperty = DependencyProperty.Register(
|
||||
"IsDropDownOpen", typeof(bool), typeof(CheckComboBox), new PropertyMetadata(ValueBoxes.FalseBox, OnIsDropDownOpenChanged));
|
||||
|
||||
private static void OnIsDropDownOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (CheckComboBox) d;
|
||||
|
||||
if (!(bool) e.NewValue)
|
||||
ctl.Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
ctl.Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
Mouse.Capture(null);
|
||||
}), DispatcherPriority.Send);
|
||||
Mouse.Capture(null);
|
||||
}), DispatcherPriority.Send);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDropDownOpen
|
||||
{
|
||||
get => (bool) GetValue(IsDropDownOpenProperty);
|
||||
set => SetValue(IsDropDownOpenProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TagStyleProperty = DependencyProperty.Register(
|
||||
"TagStyle", typeof(Style), typeof(CheckComboBox), new PropertyMetadata(default(Style)));
|
||||
|
||||
public Style TagStyle
|
||||
{
|
||||
get => (Style) GetValue(TagStyleProperty);
|
||||
set => SetValue(TagStyleProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowSelectAllButtonProperty = DependencyProperty.Register(
|
||||
"ShowSelectAllButton", typeof(bool), typeof(CheckComboBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool ShowSelectAllButton
|
||||
{
|
||||
get => (bool) GetValue(ShowSelectAllButtonProperty);
|
||||
set => SetValue(ShowSelectAllButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public CheckComboBox()
|
||||
{
|
||||
AddHandler(Controls.Tag.ClosedEvent, new RoutedEventHandler(Tags_OnClosed));
|
||||
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
|
||||
{
|
||||
SetCurrentValue(SelectedValueProperty, null);
|
||||
SetCurrentValue(SelectedItemProperty, null);
|
||||
SetCurrentValue(SelectedIndexProperty, -1);
|
||||
SelectedItems.Clear();
|
||||
}));
|
||||
|
||||
ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
|
||||
}
|
||||
|
||||
private void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
|
||||
{
|
||||
UpdateTags();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
if (_selectAllItem != null)
|
||||
{
|
||||
_selectAllItem.Selected -= SelectAllItem_Selected;
|
||||
_selectAllItem.Unselected -= SelectAllItem_Unselected;
|
||||
}
|
||||
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_panel = GetTemplateChild(ElementPanel) as Panel;
|
||||
_selectAllItem = GetTemplateChild(ElementSelectAll) as CheckComboBoxItem;
|
||||
if (_selectAllItem != null)
|
||||
{
|
||||
_selectAllItem.Selected += SelectAllItem_Selected;
|
||||
_selectAllItem.Unselected += SelectAllItem_Unselected;
|
||||
}
|
||||
|
||||
Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
IsDropDownOpen = true;
|
||||
IsDropDownOpen = false;
|
||||
}), DispatcherPriority.DataBind);
|
||||
}
|
||||
|
||||
public bool VerifyData()
|
||||
{
|
||||
OperationResult<bool> result;
|
||||
|
||||
if (VerifyFunc != null)
|
||||
{
|
||||
result = VerifyFunc.Invoke(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SelectedItems.Count > 0)
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDropDownOpen
|
||||
{
|
||||
get => (bool) GetValue(IsDropDownOpenProperty);
|
||||
set => SetValue(IsDropDownOpenProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TagStyleProperty = DependencyProperty.Register(
|
||||
"TagStyle", typeof(Style), typeof(CheckComboBox), new PropertyMetadata(default(Style)));
|
||||
|
||||
public Style TagStyle
|
||||
{
|
||||
get => (Style) GetValue(TagStyleProperty);
|
||||
set => SetValue(TagStyleProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowSelectAllButtonProperty = DependencyProperty.Register(
|
||||
"ShowSelectAllButton", typeof(bool), typeof(CheckComboBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool ShowSelectAllButton
|
||||
{
|
||||
get => (bool) GetValue(ShowSelectAllButtonProperty);
|
||||
set => SetValue(ShowSelectAllButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public CheckComboBox()
|
||||
{
|
||||
AddHandler(Controls.Tag.ClosedEvent, new RoutedEventHandler(Tags_OnClosed));
|
||||
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
|
||||
else if (InfoElement.GetNecessary(this))
|
||||
{
|
||||
SetCurrentValue(SelectedValueProperty, null);
|
||||
SetCurrentValue(SelectedItemProperty, null);
|
||||
SetCurrentValue(SelectedIndexProperty, -1);
|
||||
SelectedItems.Clear();
|
||||
}));
|
||||
|
||||
ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
|
||||
}
|
||||
|
||||
private void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
|
||||
{
|
||||
UpdateTags();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
if (_selectAllItem != null)
|
||||
{
|
||||
_selectAllItem.Selected -= SelectAllItem_Selected;
|
||||
_selectAllItem.Unselected -= SelectAllItem_Unselected;
|
||||
}
|
||||
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_panel = GetTemplateChild(ElementPanel) as Panel;
|
||||
_selectAllItem = GetTemplateChild(ElementSelectAll) as CheckComboBoxItem;
|
||||
if (_selectAllItem != null)
|
||||
{
|
||||
_selectAllItem.Selected += SelectAllItem_Selected;
|
||||
_selectAllItem.Unselected += SelectAllItem_Unselected;
|
||||
}
|
||||
|
||||
Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
IsDropDownOpen = true;
|
||||
IsDropDownOpen = false;
|
||||
}), DispatcherPriority.DataBind);
|
||||
}
|
||||
|
||||
public bool VerifyData()
|
||||
{
|
||||
OperationResult<bool> result;
|
||||
|
||||
if (VerifyFunc != null)
|
||||
{
|
||||
result = VerifyFunc.Invoke(null);
|
||||
result = OperationResult.Failed(Properties.Langs.Lang.IsNecessary);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SelectedItems.Count > 0)
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
else if (InfoElement.GetNecessary(this))
|
||||
{
|
||||
result = OperationResult.Failed(Properties.Langs.Lang.IsNecessary);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
}
|
||||
|
||||
var isError = !result.Data;
|
||||
var isError = !result.Data;
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.TrueBox);
|
||||
SetCurrentValue(ErrorStrProperty, result.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.TrueBox);
|
||||
SetCurrentValue(ErrorStrProperty, result.Message);
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.FalseBox);
|
||||
SetCurrentValue(ErrorStrProperty, default(string));
|
||||
}
|
||||
}
|
||||
|
||||
return !isError;
|
||||
}
|
||||
|
||||
public Func<string, OperationResult<bool>> VerifyFunc { get; set; }
|
||||
|
||||
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
|
||||
{
|
||||
UpdateTags();
|
||||
VerifyData();
|
||||
|
||||
base.OnSelectionChanged(e);
|
||||
}
|
||||
|
||||
protected override bool IsItemItsOwnContainerOverride(object item) => item is CheckComboBoxItem;
|
||||
|
||||
protected override DependencyObject GetContainerForItemOverride() => new CheckComboBoxItem();
|
||||
|
||||
protected override void OnDisplayMemberPathChanged(string oldDisplayMemberPath, string newDisplayMemberPath) => UpdateTags();
|
||||
|
||||
private void Tags_OnClosed(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (e.OriginalSource is Tag { Tag: CheckComboBoxItem checkComboBoxItem })
|
||||
{
|
||||
checkComboBoxItem.SetCurrentValue(IsSelectedProperty, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void SwitchAllItems(bool selected)
|
||||
{
|
||||
if (_isInternalAction) return;
|
||||
_isInternalAction = true;
|
||||
|
||||
foreach (var item in Items)
|
||||
{
|
||||
if (ItemContainerGenerator.ContainerFromItem(item) is CheckComboBoxItem checkComboBoxItem)
|
||||
{
|
||||
checkComboBoxItem.SetCurrentValue(ListBoxItem.IsSelectedProperty, selected);
|
||||
}
|
||||
}
|
||||
|
||||
_isInternalAction = false;
|
||||
UpdateTags();
|
||||
}
|
||||
|
||||
private void SelectAllItem_Selected(object sender, RoutedEventArgs e) => SwitchAllItems(true);
|
||||
|
||||
private void SelectAllItem_Unselected(object sender, RoutedEventArgs e) => SwitchAllItems(false);
|
||||
|
||||
private void UpdateTags()
|
||||
{
|
||||
if (_panel == null || _isInternalAction) return;
|
||||
|
||||
if (_selectAllItem != null)
|
||||
{
|
||||
_isInternalAction = true;
|
||||
_selectAllItem.SetCurrentValue(IsSelectedProperty, SelectedItems.Count == Items.Count);
|
||||
_isInternalAction = false;
|
||||
}
|
||||
|
||||
_panel.Children.Clear();
|
||||
|
||||
foreach (var item in SelectedItems)
|
||||
{
|
||||
if (ItemContainerGenerator.ContainerFromItem(item) is CheckComboBoxItem checkComboBoxItem)
|
||||
{
|
||||
var tag = new Tag
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
Style = TagStyle,
|
||||
Tag = checkComboBoxItem
|
||||
};
|
||||
|
||||
if (ItemsSource != null)
|
||||
{
|
||||
tag.SetBinding(ContentControl.ContentProperty, new Binding(DisplayMemberPath) { Source = item });
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.FalseBox);
|
||||
SetCurrentValue(ErrorStrProperty, default(string));
|
||||
tag.Content = checkComboBoxItem.Content;
|
||||
}
|
||||
}
|
||||
|
||||
return !isError;
|
||||
}
|
||||
|
||||
public Func<string, OperationResult<bool>> VerifyFunc { get; set; }
|
||||
|
||||
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
|
||||
{
|
||||
UpdateTags();
|
||||
VerifyData();
|
||||
|
||||
base.OnSelectionChanged(e);
|
||||
}
|
||||
|
||||
protected override bool IsItemItsOwnContainerOverride(object item) => item is CheckComboBoxItem;
|
||||
|
||||
protected override DependencyObject GetContainerForItemOverride() => new CheckComboBoxItem();
|
||||
|
||||
protected override void OnDisplayMemberPathChanged(string oldDisplayMemberPath, string newDisplayMemberPath) => UpdateTags();
|
||||
|
||||
private void Tags_OnClosed(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (e.OriginalSource is Tag { Tag: CheckComboBoxItem checkComboBoxItem })
|
||||
{
|
||||
checkComboBoxItem.SetCurrentValue(IsSelectedProperty, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void SwitchAllItems(bool selected)
|
||||
{
|
||||
if (_isInternalAction) return;
|
||||
_isInternalAction = true;
|
||||
|
||||
foreach (var item in Items)
|
||||
{
|
||||
if (ItemContainerGenerator.ContainerFromItem(item) is CheckComboBoxItem checkComboBoxItem)
|
||||
{
|
||||
checkComboBoxItem.SetCurrentValue(ListBoxItem.IsSelectedProperty, selected);
|
||||
}
|
||||
}
|
||||
|
||||
_isInternalAction = false;
|
||||
UpdateTags();
|
||||
}
|
||||
|
||||
private void SelectAllItem_Selected(object sender, RoutedEventArgs e) => SwitchAllItems(true);
|
||||
|
||||
private void SelectAllItem_Unselected(object sender, RoutedEventArgs e) => SwitchAllItems(false);
|
||||
|
||||
private void UpdateTags()
|
||||
{
|
||||
if (_panel == null || _isInternalAction) return;
|
||||
|
||||
if (_selectAllItem != null)
|
||||
{
|
||||
_isInternalAction = true;
|
||||
_selectAllItem.SetCurrentValue(IsSelectedProperty, SelectedItems.Count == Items.Count);
|
||||
_isInternalAction = false;
|
||||
}
|
||||
|
||||
_panel.Children.Clear();
|
||||
|
||||
foreach (var item in SelectedItems)
|
||||
{
|
||||
if (ItemContainerGenerator.ContainerFromItem(item) is CheckComboBoxItem checkComboBoxItem)
|
||||
{
|
||||
var tag = new Tag
|
||||
{
|
||||
Style = TagStyle,
|
||||
Tag = checkComboBoxItem
|
||||
};
|
||||
|
||||
if (ItemsSource != null)
|
||||
{
|
||||
tag.SetBinding(ContentControl.ContentProperty, new Binding(DisplayMemberPath) { Source = item });
|
||||
}
|
||||
else
|
||||
{
|
||||
tag.Content = checkComboBoxItem.Content;
|
||||
}
|
||||
|
||||
_panel.Children.Add(tag);
|
||||
}
|
||||
_panel.Children.Add(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class CheckComboBoxItem : ListBoxItem
|
||||
{
|
||||
public class CheckComboBoxItem : ListBoxItem
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -12,435 +12,434 @@ using System.Windows.Threading;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Interactivity;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
[TemplatePart(Name = AutoCompletePanel, Type = typeof(Panel))]
|
||||
[TemplatePart(Name = EditableTextBox, Type = typeof(System.Windows.Controls.TextBox))]
|
||||
[TemplatePart(Name = AutoPopupAutoComplete, Type = typeof(Popup))]
|
||||
public class ComboBox : System.Windows.Controls.ComboBox, IDataInput
|
||||
{
|
||||
[TemplatePart(Name = AutoCompletePanel, Type = typeof(Panel))]
|
||||
[TemplatePart(Name = EditableTextBox, Type = typeof(System.Windows.Controls.TextBox))]
|
||||
[TemplatePart(Name = AutoPopupAutoComplete, Type = typeof(Popup))]
|
||||
public class ComboBox : System.Windows.Controls.ComboBox, IDataInput
|
||||
{
|
||||
#if NET40
|
||||
|
||||
private string _searchText;
|
||||
private string _searchText;
|
||||
|
||||
private DispatcherTimer _autoCompleteTimer;
|
||||
private DispatcherTimer _autoCompleteTimer;
|
||||
|
||||
#endif
|
||||
private bool _isAutoCompleteAction = true;
|
||||
private bool _isAutoCompleteAction = true;
|
||||
|
||||
private Panel _autoCompletePanel;
|
||||
private Panel _autoCompletePanel;
|
||||
|
||||
private System.Windows.Controls.TextBox _editableTextBox;
|
||||
private System.Windows.Controls.TextBox _editableTextBox;
|
||||
|
||||
private Popup _autoPopupAutoComplete;
|
||||
private Popup _autoPopupAutoComplete;
|
||||
|
||||
private const string AutoCompletePanel = "PART_AutoCompletePanel";
|
||||
private const string AutoCompletePanel = "PART_AutoCompletePanel";
|
||||
|
||||
private const string AutoPopupAutoComplete = "PART_Popup_AutoComplete";
|
||||
private const string AutoPopupAutoComplete = "PART_Popup_AutoComplete";
|
||||
|
||||
private const string EditableTextBox = "PART_EditableTextBox";
|
||||
private const string EditableTextBox = "PART_EditableTextBox";
|
||||
|
||||
public ComboBox()
|
||||
public ComboBox()
|
||||
{
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
|
||||
{
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
|
||||
{
|
||||
SetCurrentValue(SelectedValueProperty, null);
|
||||
SetCurrentValue(SelectedItemProperty, null);
|
||||
SetCurrentValue(SelectedIndexProperty, -1);
|
||||
SetCurrentValue(TextProperty, "");
|
||||
}));
|
||||
SetCurrentValue(SelectedValueProperty, null);
|
||||
SetCurrentValue(SelectedItemProperty, null);
|
||||
SetCurrentValue(SelectedIndexProperty, -1);
|
||||
SetCurrentValue(TextProperty, "");
|
||||
}));
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
if (_editableTextBox != null)
|
||||
{
|
||||
BindingOperations.ClearBinding(_editableTextBox, System.Windows.Controls.TextBox.TextProperty);
|
||||
_editableTextBox.GotFocus -= EditableTextBox_GotFocus;
|
||||
_editableTextBox.LostFocus -= EditableTextBox_LostFocus;
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
base.OnApplyTemplate();
|
||||
|
||||
if (IsEditable)
|
||||
{
|
||||
_editableTextBox = GetTemplateChild(EditableTextBox) as System.Windows.Controls.TextBox;
|
||||
|
||||
if (_editableTextBox != null)
|
||||
{
|
||||
BindingOperations.ClearBinding(_editableTextBox, System.Windows.Controls.TextBox.TextProperty);
|
||||
_editableTextBox.GotFocus -= EditableTextBox_GotFocus;
|
||||
_editableTextBox.LostFocus -= EditableTextBox_LostFocus;
|
||||
}
|
||||
_editableTextBox.TextChanged += EditableTextBox_TextChanged;
|
||||
|
||||
base.OnApplyTemplate();
|
||||
|
||||
if (IsEditable)
|
||||
{
|
||||
_editableTextBox = GetTemplateChild(EditableTextBox) as System.Windows.Controls.TextBox;
|
||||
|
||||
if (_editableTextBox != null)
|
||||
{
|
||||
_editableTextBox.TextChanged += EditableTextBox_TextChanged;
|
||||
|
||||
_editableTextBox.SetBinding(SelectionBrushProperty, new Binding(SelectionBrushProperty.Name) { Source = this });
|
||||
_editableTextBox.SetBinding(SelectionBrushProperty, new Binding(SelectionBrushProperty.Name) { Source = this });
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
_editableTextBox.SetBinding(SelectionTextBrushProperty, new Binding(SelectionTextBrushProperty.Name) { Source = this });
|
||||
_editableTextBox.SetBinding(SelectionTextBrushProperty, new Binding(SelectionTextBrushProperty.Name) { Source = this });
|
||||
#endif
|
||||
_editableTextBox.SetBinding(SelectionOpacityProperty, new Binding(SelectionOpacityProperty.Name) { Source = this });
|
||||
_editableTextBox.SetBinding(CaretBrushProperty, new Binding(CaretBrushProperty.Name) { Source = this });
|
||||
_editableTextBox.SetBinding(SelectionOpacityProperty, new Binding(SelectionOpacityProperty.Name) { Source = this });
|
||||
_editableTextBox.SetBinding(CaretBrushProperty, new Binding(CaretBrushProperty.Name) { Source = this });
|
||||
|
||||
if (AutoComplete)
|
||||
{
|
||||
if (AutoComplete)
|
||||
{
|
||||
#if NET40
|
||||
_autoCompleteTimer = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromMilliseconds(500)
|
||||
};
|
||||
_autoCompleteTimer.Tick += AutoCompleteTimer_Tick;
|
||||
_autoCompleteTimer = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromMilliseconds(500)
|
||||
};
|
||||
_autoCompleteTimer.Tick += AutoCompleteTimer_Tick;
|
||||
#endif
|
||||
_autoPopupAutoComplete = GetTemplateChild(AutoPopupAutoComplete) as Popup;
|
||||
_autoCompletePanel = GetTemplateChild(AutoCompletePanel) as Panel;
|
||||
_editableTextBox.SetBinding(System.Windows.Controls.TextBox.TextProperty, new Binding(SearchTextProperty.Name)
|
||||
{
|
||||
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
|
||||
Mode = BindingMode.OneWayToSource,
|
||||
_autoPopupAutoComplete = GetTemplateChild(AutoPopupAutoComplete) as Popup;
|
||||
_autoCompletePanel = GetTemplateChild(AutoCompletePanel) as Panel;
|
||||
_editableTextBox.SetBinding(System.Windows.Controls.TextBox.TextProperty, new Binding(SearchTextProperty.Name)
|
||||
{
|
||||
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
|
||||
Mode = BindingMode.OneWayToSource,
|
||||
#if !NET40
|
||||
Delay = 500,
|
||||
Delay = 500,
|
||||
#endif
|
||||
Source = this
|
||||
});
|
||||
_editableTextBox.GotFocus += EditableTextBox_GotFocus;
|
||||
_editableTextBox.LostFocus += EditableTextBox_LostFocus;
|
||||
}
|
||||
Source = this
|
||||
});
|
||||
_editableTextBox.GotFocus += EditableTextBox_GotFocus;
|
||||
_editableTextBox.LostFocus += EditableTextBox_LostFocus;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if NET40
|
||||
|
||||
private void AutoCompleteTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
UpdateSearchItems(_searchText);
|
||||
_autoCompleteTimer.Stop();
|
||||
}
|
||||
private void AutoCompleteTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
UpdateSearchItems(_searchText);
|
||||
_autoCompleteTimer.Stop();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
private void EditableTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||
private void EditableTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
VerifyData();
|
||||
}
|
||||
|
||||
private void EditableTextBox_LostFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_autoPopupAutoComplete != null)
|
||||
{
|
||||
VerifyData();
|
||||
_autoPopupAutoComplete.IsOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
#if !NET40
|
||||
protected override void OnDropDownClosed(EventArgs e)
|
||||
{
|
||||
base.OnDropDownClosed(e);
|
||||
|
||||
_isAutoCompleteAction = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
private void EditableTextBox_GotFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_autoPopupAutoComplete != null && _editableTextBox != null &&
|
||||
!string.IsNullOrEmpty(_editableTextBox.Text))
|
||||
{
|
||||
_autoPopupAutoComplete.IsOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
|
||||
{
|
||||
_isAutoCompleteAction = false;
|
||||
base.OnSelectionChanged(e);
|
||||
VerifyData();
|
||||
#if NET40
|
||||
_isAutoCompleteAction = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据验证委托
|
||||
/// </summary>
|
||||
public Func<string, OperationResult<bool>> VerifyFunc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据搜索委托
|
||||
/// </summary>
|
||||
public Func<ItemCollection, object, IEnumerable<object>> SearchFunc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据是否错误
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register(
|
||||
"IsError", typeof(bool), typeof(ComboBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
/// <summary>
|
||||
/// 数据是否错误
|
||||
/// </summary>
|
||||
public bool IsError
|
||||
{
|
||||
get => (bool) GetValue(IsErrorProperty);
|
||||
set => SetValue(IsErrorProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 错误提示
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ErrorStrProperty = DependencyProperty.Register(
|
||||
"ErrorStr", typeof(string), typeof(ComboBox), new PropertyMetadata(default(string)));
|
||||
|
||||
/// <summary>
|
||||
/// 错误提示
|
||||
/// </summary>
|
||||
public string ErrorStr
|
||||
{
|
||||
get => (string) GetValue(ErrorStrProperty);
|
||||
set => SetValue(ErrorStrProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
public static readonly DependencyPropertyKey TextTypePropertyKey =
|
||||
DependencyProperty.RegisterReadOnly("TextType", typeof(TextType), typeof(ComboBox),
|
||||
new PropertyMetadata(default(TextType)));
|
||||
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TextTypeProperty = TextTypePropertyKey.DependencyProperty;
|
||||
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
public TextType TextType
|
||||
{
|
||||
get => (TextType) GetValue(TextTypeProperty);
|
||||
set => SetValue(TextTypeProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示清除按钮
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ShowClearButtonProperty = DependencyProperty.Register(
|
||||
"ShowClearButton", typeof(bool), typeof(ComboBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示清除按钮
|
||||
/// </summary>
|
||||
public bool ShowClearButton
|
||||
{
|
||||
get => (bool) GetValue(ShowClearButtonProperty);
|
||||
set => SetValue(ShowClearButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否自动完成输入
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty AutoCompleteProperty = DependencyProperty.Register(
|
||||
"AutoComplete", typeof(bool), typeof(ComboBox), new PropertyMetadata(ValueBoxes.FalseBox, OnAutoCompleteChanged));
|
||||
|
||||
private static void OnAutoCompleteChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (ComboBox) d;
|
||||
if (ctl._editableTextBox != null)
|
||||
{
|
||||
ctl.UpdateSearchItems(ctl._editableTextBox.Text);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否自动完成输入
|
||||
/// </summary>
|
||||
public bool AutoComplete
|
||||
{
|
||||
get => (bool) GetValue(AutoCompleteProperty);
|
||||
set => SetValue(AutoCompleteProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 搜索文本
|
||||
/// </summary>
|
||||
internal static readonly DependencyProperty SearchTextProperty = DependencyProperty.Register(
|
||||
"SearchText", typeof(string), typeof(ComboBox), new PropertyMetadata(default(string), OnSearchTextChanged));
|
||||
|
||||
private static void OnSearchTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (ComboBox) d;
|
||||
if (ctl._isAutoCompleteAction)
|
||||
{
|
||||
#if NET40
|
||||
ctl._searchText = e.NewValue as string;
|
||||
ctl._autoCompleteTimer.Stop();
|
||||
ctl._autoCompleteTimer.Start();
|
||||
#else
|
||||
ctl.UpdateSearchItems(e.NewValue as string);
|
||||
#endif
|
||||
}
|
||||
|
||||
private void EditableTextBox_LostFocus(object sender, RoutedEventArgs e)
|
||||
ctl._isAutoCompleteAction = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 搜索文本
|
||||
/// </summary>
|
||||
internal string SearchText
|
||||
{
|
||||
get => (string) GetValue(SearchTextProperty);
|
||||
set => SetValue(SearchTextProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectionBrushProperty =
|
||||
TextBoxBase.SelectionBrushProperty.AddOwner(typeof(ComboBox));
|
||||
|
||||
public Brush SelectionBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionBrushProperty);
|
||||
set => SetValue(SelectionBrushProperty, value);
|
||||
}
|
||||
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
|
||||
public static readonly DependencyProperty SelectionTextBrushProperty =
|
||||
TextBoxBase.SelectionTextBrushProperty.AddOwner(typeof(ComboBox));
|
||||
|
||||
public Brush SelectionTextBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionTextBrushProperty);
|
||||
set => SetValue(SelectionTextBrushProperty, value);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public static readonly DependencyProperty SelectionOpacityProperty =
|
||||
TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(ComboBox));
|
||||
|
||||
public double SelectionOpacity
|
||||
{
|
||||
get => (double) GetValue(SelectionOpacityProperty);
|
||||
set => SetValue(SelectionOpacityProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CaretBrushProperty =
|
||||
TextBoxBase.CaretBrushProperty.AddOwner(typeof(ComboBox));
|
||||
|
||||
public Brush CaretBrush
|
||||
{
|
||||
get => (Brush) GetValue(CaretBrushProperty);
|
||||
set => SetValue(CaretBrushProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual bool VerifyData()
|
||||
{
|
||||
OperationResult<bool> result;
|
||||
|
||||
var value = _editableTextBox == null ? Text : _editableTextBox.Text;
|
||||
|
||||
if (VerifyFunc != null)
|
||||
{
|
||||
result = VerifyFunc.Invoke(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
else if (InfoElement.GetNecessary(this))
|
||||
{
|
||||
result = OperationResult.Failed(Properties.Langs.Lang.IsNecessary);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
}
|
||||
|
||||
var isError = !result.Data;
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.TrueBox);
|
||||
SetCurrentValue(ErrorStrProperty, result.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.FalseBox);
|
||||
SetCurrentValue(ErrorStrProperty, default(string));
|
||||
}
|
||||
}
|
||||
|
||||
return !isError;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新搜索的项目
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
private void UpdateSearchItems(string key)
|
||||
{
|
||||
if (_editableTextBox != null && _autoPopupAutoComplete != null)
|
||||
{
|
||||
_autoPopupAutoComplete.IsOpen = !string.IsNullOrEmpty(key);
|
||||
_autoCompletePanel.Children.Clear();
|
||||
|
||||
if (SearchFunc == null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
{
|
||||
foreach (var item in Items)
|
||||
{
|
||||
var content = item?.ToString();
|
||||
if (content == null) continue;
|
||||
if (!content.Contains(key)) continue;
|
||||
|
||||
_autoCompletePanel.Children.Add(CreateSearchItem(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in SearchFunc.Invoke(Items, key))
|
||||
{
|
||||
_autoCompletePanel.Children.Add(CreateSearchItem(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ComboBoxItem CreateSearchItem(object content)
|
||||
{
|
||||
var item = new ComboBoxItem
|
||||
{
|
||||
Content = content,
|
||||
Style = ItemContainerStyle,
|
||||
ContentTemplate = ItemTemplate
|
||||
};
|
||||
|
||||
item.PreviewMouseLeftButtonDown += AutoCompleteItem_PreviewMouseLeftButtonDown;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
private void AutoCompleteItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (sender is ComboBoxItem comboBoxItem)
|
||||
{
|
||||
if (_autoPopupAutoComplete != null)
|
||||
{
|
||||
_autoPopupAutoComplete.IsOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
#if !NET40
|
||||
protected override void OnDropDownClosed(EventArgs e)
|
||||
{
|
||||
base.OnDropDownClosed(e);
|
||||
|
||||
_isAutoCompleteAction = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
private void EditableTextBox_GotFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_autoPopupAutoComplete != null && _editableTextBox != null &&
|
||||
!string.IsNullOrEmpty(_editableTextBox.Text))
|
||||
{
|
||||
_autoPopupAutoComplete.IsOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
|
||||
{
|
||||
_isAutoCompleteAction = false;
|
||||
base.OnSelectionChanged(e);
|
||||
VerifyData();
|
||||
#if NET40
|
||||
_isAutoCompleteAction = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据验证委托
|
||||
/// </summary>
|
||||
public Func<string, OperationResult<bool>> VerifyFunc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据搜索委托
|
||||
/// </summary>
|
||||
public Func<ItemCollection, object, IEnumerable<object>> SearchFunc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据是否错误
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register(
|
||||
"IsError", typeof(bool), typeof(ComboBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
/// <summary>
|
||||
/// 数据是否错误
|
||||
/// </summary>
|
||||
public bool IsError
|
||||
{
|
||||
get => (bool) GetValue(IsErrorProperty);
|
||||
set => SetValue(IsErrorProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 错误提示
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ErrorStrProperty = DependencyProperty.Register(
|
||||
"ErrorStr", typeof(string), typeof(ComboBox), new PropertyMetadata(default(string)));
|
||||
|
||||
/// <summary>
|
||||
/// 错误提示
|
||||
/// </summary>
|
||||
public string ErrorStr
|
||||
{
|
||||
get => (string) GetValue(ErrorStrProperty);
|
||||
set => SetValue(ErrorStrProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
public static readonly DependencyPropertyKey TextTypePropertyKey =
|
||||
DependencyProperty.RegisterReadOnly("TextType", typeof(TextType), typeof(ComboBox),
|
||||
new PropertyMetadata(default(TextType)));
|
||||
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TextTypeProperty = TextTypePropertyKey.DependencyProperty;
|
||||
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
public TextType TextType
|
||||
{
|
||||
get => (TextType) GetValue(TextTypeProperty);
|
||||
set => SetValue(TextTypeProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示清除按钮
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ShowClearButtonProperty = DependencyProperty.Register(
|
||||
"ShowClearButton", typeof(bool), typeof(ComboBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示清除按钮
|
||||
/// </summary>
|
||||
public bool ShowClearButton
|
||||
{
|
||||
get => (bool) GetValue(ShowClearButtonProperty);
|
||||
set => SetValue(ShowClearButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否自动完成输入
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty AutoCompleteProperty = DependencyProperty.Register(
|
||||
"AutoComplete", typeof(bool), typeof(ComboBox), new PropertyMetadata(ValueBoxes.FalseBox, OnAutoCompleteChanged));
|
||||
|
||||
private static void OnAutoCompleteChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (ComboBox) d;
|
||||
if (ctl._editableTextBox != null)
|
||||
{
|
||||
ctl.UpdateSearchItems(ctl._editableTextBox.Text);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否自动完成输入
|
||||
/// </summary>
|
||||
public bool AutoComplete
|
||||
{
|
||||
get => (bool) GetValue(AutoCompleteProperty);
|
||||
set => SetValue(AutoCompleteProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 搜索文本
|
||||
/// </summary>
|
||||
internal static readonly DependencyProperty SearchTextProperty = DependencyProperty.Register(
|
||||
"SearchText", typeof(string), typeof(ComboBox), new PropertyMetadata(default(string), OnSearchTextChanged));
|
||||
|
||||
private static void OnSearchTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (ComboBox) d;
|
||||
if (ctl._isAutoCompleteAction)
|
||||
{
|
||||
#if NET40
|
||||
ctl._searchText = e.NewValue as string;
|
||||
ctl._autoCompleteTimer.Stop();
|
||||
ctl._autoCompleteTimer.Start();
|
||||
#else
|
||||
ctl.UpdateSearchItems(e.NewValue as string);
|
||||
#endif
|
||||
}
|
||||
|
||||
ctl._isAutoCompleteAction = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 搜索文本
|
||||
/// </summary>
|
||||
internal string SearchText
|
||||
{
|
||||
get => (string) GetValue(SearchTextProperty);
|
||||
set => SetValue(SearchTextProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectionBrushProperty =
|
||||
TextBoxBase.SelectionBrushProperty.AddOwner(typeof(ComboBox));
|
||||
|
||||
public Brush SelectionBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionBrushProperty);
|
||||
set => SetValue(SelectionBrushProperty, value);
|
||||
}
|
||||
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
|
||||
public static readonly DependencyProperty SelectionTextBrushProperty =
|
||||
TextBoxBase.SelectionTextBrushProperty.AddOwner(typeof(ComboBox));
|
||||
|
||||
public Brush SelectionTextBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionTextBrushProperty);
|
||||
set => SetValue(SelectionTextBrushProperty, value);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public static readonly DependencyProperty SelectionOpacityProperty =
|
||||
TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(ComboBox));
|
||||
|
||||
public double SelectionOpacity
|
||||
{
|
||||
get => (double) GetValue(SelectionOpacityProperty);
|
||||
set => SetValue(SelectionOpacityProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CaretBrushProperty =
|
||||
TextBoxBase.CaretBrushProperty.AddOwner(typeof(ComboBox));
|
||||
|
||||
public Brush CaretBrush
|
||||
{
|
||||
get => (Brush) GetValue(CaretBrushProperty);
|
||||
set => SetValue(CaretBrushProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual bool VerifyData()
|
||||
{
|
||||
OperationResult<bool> result;
|
||||
|
||||
var value = _editableTextBox == null ? Text : _editableTextBox.Text;
|
||||
|
||||
if (VerifyFunc != null)
|
||||
{
|
||||
result = VerifyFunc.Invoke(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
else if (InfoElement.GetNecessary(this))
|
||||
{
|
||||
result = OperationResult.Failed(Properties.Langs.Lang.IsNecessary);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
}
|
||||
|
||||
var isError = !result.Data;
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.TrueBox);
|
||||
SetCurrentValue(ErrorStrProperty, result.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.FalseBox);
|
||||
SetCurrentValue(ErrorStrProperty, default(string));
|
||||
}
|
||||
}
|
||||
|
||||
return !isError;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新搜索的项目
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
private void UpdateSearchItems(string key)
|
||||
{
|
||||
if (_editableTextBox != null && _autoPopupAutoComplete != null)
|
||||
{
|
||||
_autoPopupAutoComplete.IsOpen = !string.IsNullOrEmpty(key);
|
||||
_autoCompletePanel.Children.Clear();
|
||||
|
||||
if (SearchFunc == null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
{
|
||||
foreach (var item in Items)
|
||||
{
|
||||
var content = item?.ToString();
|
||||
if (content == null) continue;
|
||||
if (!content.Contains(key)) continue;
|
||||
|
||||
_autoCompletePanel.Children.Add(CreateSearchItem(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in SearchFunc.Invoke(Items, key))
|
||||
{
|
||||
_autoCompletePanel.Children.Add(CreateSearchItem(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ComboBoxItem CreateSearchItem(object content)
|
||||
{
|
||||
var item = new ComboBoxItem
|
||||
{
|
||||
Content = content,
|
||||
Style = ItemContainerStyle,
|
||||
ContentTemplate = ItemTemplate
|
||||
};
|
||||
|
||||
item.PreviewMouseLeftButtonDown += AutoCompleteItem_PreviewMouseLeftButtonDown;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
private void AutoCompleteItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (sender is ComboBoxItem comboBoxItem)
|
||||
{
|
||||
if (_autoPopupAutoComplete != null)
|
||||
{
|
||||
_autoPopupAutoComplete.IsOpen = false;
|
||||
}
|
||||
|
||||
_isAutoCompleteAction = false;
|
||||
SelectedValue = comboBoxItem.Content;
|
||||
}
|
||||
SelectedValue = comboBoxItem.Content;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,171 +8,170 @@ using System.Windows.Media;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Interactivity;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
[TemplatePart(Name = ElementTextBox, Type = typeof(DatePickerTextBox))]
|
||||
public class DatePicker : System.Windows.Controls.DatePicker, IDataInput
|
||||
{
|
||||
[TemplatePart(Name = ElementTextBox, Type = typeof(DatePickerTextBox))]
|
||||
public class DatePicker : System.Windows.Controls.DatePicker, IDataInput
|
||||
private const string ElementTextBox = "PART_TextBox";
|
||||
|
||||
private System.Windows.Controls.TextBox _textBox;
|
||||
|
||||
public DatePicker()
|
||||
{
|
||||
private const string ElementTextBox = "PART_TextBox";
|
||||
|
||||
private System.Windows.Controls.TextBox _textBox;
|
||||
|
||||
public DatePicker()
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
|
||||
{
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
|
||||
{
|
||||
SetCurrentValue(SelectedDateProperty, null);
|
||||
SetCurrentValue(TextProperty, "");
|
||||
}));
|
||||
SetCurrentValue(SelectedDateProperty, null);
|
||||
SetCurrentValue(TextProperty, "");
|
||||
}));
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
if (_textBox != null)
|
||||
{
|
||||
_textBox.TextChanged -= TextBox_TextChanged;
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_textBox = GetTemplateChild(ElementTextBox) as System.Windows.Controls.TextBox;
|
||||
if (_textBox != null)
|
||||
{
|
||||
if (_textBox != null)
|
||||
{
|
||||
_textBox.TextChanged -= TextBox_TextChanged;
|
||||
}
|
||||
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_textBox = GetTemplateChild(ElementTextBox) as System.Windows.Controls.TextBox;
|
||||
if (_textBox != null)
|
||||
{
|
||||
_textBox.SetBinding(SelectionBrushProperty, new Binding(SelectionBrushProperty.Name) { Source = this });
|
||||
_textBox.SetBinding(SelectionBrushProperty, new Binding(SelectionBrushProperty.Name) { Source = this });
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
_textBox.SetBinding(SelectionTextBrushProperty, new Binding(SelectionTextBrushProperty.Name) { Source = this });
|
||||
_textBox.SetBinding(SelectionTextBrushProperty, new Binding(SelectionTextBrushProperty.Name) { Source = this });
|
||||
#endif
|
||||
_textBox.SetBinding(SelectionOpacityProperty, new Binding(SelectionOpacityProperty.Name) { Source = this });
|
||||
_textBox.SetBinding(CaretBrushProperty, new Binding(CaretBrushProperty.Name) { Source = this });
|
||||
_textBox.SetBinding(SelectionOpacityProperty, new Binding(SelectionOpacityProperty.Name) { Source = this });
|
||||
_textBox.SetBinding(CaretBrushProperty, new Binding(CaretBrushProperty.Name) { Source = this });
|
||||
|
||||
_textBox.TextChanged += TextBox_TextChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void TextBox_TextChanged(object sender, TextChangedEventArgs e) => VerifyData();
|
||||
|
||||
public Func<string, OperationResult<bool>> VerifyFunc { get; set; }
|
||||
|
||||
public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register(
|
||||
"IsError", typeof(bool), typeof(DatePicker), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool IsError
|
||||
{
|
||||
get => (bool) GetValue(IsErrorProperty);
|
||||
set => SetValue(IsErrorProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ErrorStrProperty = DependencyProperty.Register(
|
||||
"ErrorStr", typeof(string), typeof(DatePicker), new PropertyMetadata(default(string)));
|
||||
|
||||
public string ErrorStr
|
||||
{
|
||||
get => (string) GetValue(ErrorStrProperty);
|
||||
set => SetValue(ErrorStrProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextTypeProperty = DependencyProperty.Register(
|
||||
"TextType", typeof(TextType), typeof(DatePicker), new PropertyMetadata(default(TextType)));
|
||||
|
||||
public TextType TextType
|
||||
{
|
||||
get => (TextType) GetValue(TextTypeProperty);
|
||||
set => SetValue(TextTypeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowClearButtonProperty = DependencyProperty.Register(
|
||||
"ShowClearButton", typeof(bool), typeof(DatePicker), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool ShowClearButton
|
||||
{
|
||||
get => (bool) GetValue(ShowClearButtonProperty);
|
||||
set => SetValue(ShowClearButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectionBrushProperty =
|
||||
TextBoxBase.SelectionBrushProperty.AddOwner(typeof(DatePicker));
|
||||
|
||||
public Brush SelectionBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionBrushProperty);
|
||||
set => SetValue(SelectionBrushProperty, value);
|
||||
}
|
||||
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
|
||||
public static readonly DependencyProperty SelectionTextBrushProperty =
|
||||
TextBoxBase.SelectionTextBrushProperty.AddOwner(typeof(DatePicker));
|
||||
|
||||
public Brush SelectionTextBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionTextBrushProperty);
|
||||
set => SetValue(SelectionTextBrushProperty, value);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public static readonly DependencyProperty SelectionOpacityProperty =
|
||||
TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(DatePicker));
|
||||
|
||||
public double SelectionOpacity
|
||||
{
|
||||
get => (double) GetValue(SelectionOpacityProperty);
|
||||
set => SetValue(SelectionOpacityProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CaretBrushProperty =
|
||||
TextBoxBase.CaretBrushProperty.AddOwner(typeof(DatePicker));
|
||||
|
||||
public Brush CaretBrush
|
||||
{
|
||||
get => (Brush) GetValue(CaretBrushProperty);
|
||||
set => SetValue(CaretBrushProperty, value);
|
||||
}
|
||||
|
||||
public virtual bool VerifyData()
|
||||
{
|
||||
OperationResult<bool> result;
|
||||
|
||||
if (VerifyFunc != null)
|
||||
{
|
||||
result = VerifyFunc.Invoke(Text);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
else if (InfoElement.GetNecessary(this))
|
||||
{
|
||||
result = OperationResult.Failed(Properties.Langs.Lang.IsNecessary);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
}
|
||||
|
||||
var isError = !result.Data;
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.TrueBox);
|
||||
SetCurrentValue(ErrorStrProperty, result.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.FalseBox);
|
||||
SetCurrentValue(ErrorStrProperty, default(string));
|
||||
}
|
||||
}
|
||||
return !isError;
|
||||
_textBox.TextChanged += TextBox_TextChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void TextBox_TextChanged(object sender, TextChangedEventArgs e) => VerifyData();
|
||||
|
||||
public Func<string, OperationResult<bool>> VerifyFunc { get; set; }
|
||||
|
||||
public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register(
|
||||
"IsError", typeof(bool), typeof(DatePicker), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool IsError
|
||||
{
|
||||
get => (bool) GetValue(IsErrorProperty);
|
||||
set => SetValue(IsErrorProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ErrorStrProperty = DependencyProperty.Register(
|
||||
"ErrorStr", typeof(string), typeof(DatePicker), new PropertyMetadata(default(string)));
|
||||
|
||||
public string ErrorStr
|
||||
{
|
||||
get => (string) GetValue(ErrorStrProperty);
|
||||
set => SetValue(ErrorStrProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextTypeProperty = DependencyProperty.Register(
|
||||
"TextType", typeof(TextType), typeof(DatePicker), new PropertyMetadata(default(TextType)));
|
||||
|
||||
public TextType TextType
|
||||
{
|
||||
get => (TextType) GetValue(TextTypeProperty);
|
||||
set => SetValue(TextTypeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowClearButtonProperty = DependencyProperty.Register(
|
||||
"ShowClearButton", typeof(bool), typeof(DatePicker), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool ShowClearButton
|
||||
{
|
||||
get => (bool) GetValue(ShowClearButtonProperty);
|
||||
set => SetValue(ShowClearButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectionBrushProperty =
|
||||
TextBoxBase.SelectionBrushProperty.AddOwner(typeof(DatePicker));
|
||||
|
||||
public Brush SelectionBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionBrushProperty);
|
||||
set => SetValue(SelectionBrushProperty, value);
|
||||
}
|
||||
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
|
||||
public static readonly DependencyProperty SelectionTextBrushProperty =
|
||||
TextBoxBase.SelectionTextBrushProperty.AddOwner(typeof(DatePicker));
|
||||
|
||||
public Brush SelectionTextBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionTextBrushProperty);
|
||||
set => SetValue(SelectionTextBrushProperty, value);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public static readonly DependencyProperty SelectionOpacityProperty =
|
||||
TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(DatePicker));
|
||||
|
||||
public double SelectionOpacity
|
||||
{
|
||||
get => (double) GetValue(SelectionOpacityProperty);
|
||||
set => SetValue(SelectionOpacityProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CaretBrushProperty =
|
||||
TextBoxBase.CaretBrushProperty.AddOwner(typeof(DatePicker));
|
||||
|
||||
public Brush CaretBrush
|
||||
{
|
||||
get => (Brush) GetValue(CaretBrushProperty);
|
||||
set => SetValue(CaretBrushProperty, value);
|
||||
}
|
||||
|
||||
public virtual bool VerifyData()
|
||||
{
|
||||
OperationResult<bool> result;
|
||||
|
||||
if (VerifyFunc != null)
|
||||
{
|
||||
result = VerifyFunc.Invoke(Text);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
else if (InfoElement.GetNecessary(this))
|
||||
{
|
||||
result = OperationResult.Failed(Properties.Langs.Lang.IsNecessary);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
}
|
||||
|
||||
var isError = !result.Data;
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.TrueBox);
|
||||
SetCurrentValue(ErrorStrProperty, result.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.FalseBox);
|
||||
SetCurrentValue(ErrorStrProperty, default(string));
|
||||
}
|
||||
}
|
||||
return !isError;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -2,42 +2,41 @@
|
||||
using HandyControl.Data;
|
||||
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// 表示可以成为一个数据输入控件
|
||||
/// </summary>
|
||||
public interface IDataInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示可以成为一个数据输入控件
|
||||
/// 验证数据
|
||||
/// </summary>
|
||||
public interface IDataInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 验证数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
bool VerifyData();
|
||||
/// <returns></returns>
|
||||
bool VerifyData();
|
||||
|
||||
/// <summary>
|
||||
/// 数据验证委托
|
||||
/// </summary>
|
||||
Func<string, OperationResult<bool>> VerifyFunc { get; set; }
|
||||
/// <summary>
|
||||
/// 数据验证委托
|
||||
/// </summary>
|
||||
Func<string, OperationResult<bool>> VerifyFunc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据是否错误
|
||||
/// </summary>
|
||||
bool IsError { get; set; }
|
||||
/// <summary>
|
||||
/// 数据是否错误
|
||||
/// </summary>
|
||||
bool IsError { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 错误提示
|
||||
/// </summary>
|
||||
string ErrorStr { get; set; }
|
||||
/// <summary>
|
||||
/// 错误提示
|
||||
/// </summary>
|
||||
string ErrorStr { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
TextType TextType { get; set; }
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
TextType TextType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示清除按钮
|
||||
/// </summary>
|
||||
bool ShowClearButton { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 是否显示清除按钮
|
||||
/// </summary>
|
||||
bool ShowClearButton { get; set; }
|
||||
}
|
||||
@@ -8,130 +8,129 @@ using HandyControl.Data;
|
||||
using HandyControl.Interactivity;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class ImageSelector : Control
|
||||
{
|
||||
public class ImageSelector : Control
|
||||
public static readonly RoutedEvent ImageSelectedEvent =
|
||||
EventManager.RegisterRoutedEvent("ImageSelected", RoutingStrategy.Bubble,
|
||||
typeof(RoutedEventHandler), typeof(ImageSelector));
|
||||
|
||||
public event RoutedEventHandler ImageSelected
|
||||
{
|
||||
public static readonly RoutedEvent ImageSelectedEvent =
|
||||
EventManager.RegisterRoutedEvent("ImageSelected", RoutingStrategy.Bubble,
|
||||
typeof(RoutedEventHandler), typeof(ImageSelector));
|
||||
add => AddHandler(ImageSelectedEvent, value);
|
||||
remove => RemoveHandler(ImageSelectedEvent, value);
|
||||
}
|
||||
|
||||
public event RoutedEventHandler ImageSelected
|
||||
public ImageSelector() => CommandBindings.Add(new CommandBinding(ControlCommands.Switch, SwitchImage));
|
||||
|
||||
private void SwitchImage(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
if (!HasValue)
|
||||
{
|
||||
add => AddHandler(ImageSelectedEvent, value);
|
||||
remove => RemoveHandler(ImageSelectedEvent, value);
|
||||
}
|
||||
|
||||
public ImageSelector() => CommandBindings.Add(new CommandBinding(ControlCommands.Switch, SwitchImage));
|
||||
|
||||
private void SwitchImage(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
if (!HasValue)
|
||||
var dialog = new OpenFileDialog
|
||||
{
|
||||
var dialog = new OpenFileDialog
|
||||
{
|
||||
RestoreDirectory = true,
|
||||
Filter = Filter,
|
||||
DefaultExt = DefaultExt
|
||||
};
|
||||
RestoreDirectory = true,
|
||||
Filter = Filter,
|
||||
DefaultExt = DefaultExt
|
||||
};
|
||||
|
||||
if (dialog.ShowDialog() == true)
|
||||
{
|
||||
SetValue(UriPropertyKey, new Uri(dialog.FileName, UriKind.RelativeOrAbsolute));
|
||||
SetValue(PreviewBrushPropertyKey, new ImageBrush(BitmapFrame.Create(Uri, BitmapCreateOptions.IgnoreImageCache, BitmapCacheOption.None))
|
||||
{
|
||||
Stretch = Stretch
|
||||
});
|
||||
SetValue(HasValuePropertyKey, ValueBoxes.TrueBox);
|
||||
SetCurrentValue(ToolTipProperty, dialog.FileName);
|
||||
RaiseEvent(new RoutedEventArgs(ImageSelectedEvent, this));
|
||||
}
|
||||
}
|
||||
else
|
||||
if (dialog.ShowDialog() == true)
|
||||
{
|
||||
SetValue(UriPropertyKey, default(Uri));
|
||||
SetValue(PreviewBrushPropertyKey, default(Brush));
|
||||
SetValue(HasValuePropertyKey, ValueBoxes.FalseBox);
|
||||
SetCurrentValue(ToolTipProperty, default);
|
||||
SetValue(UriPropertyKey, new Uri(dialog.FileName, UriKind.RelativeOrAbsolute));
|
||||
SetValue(PreviewBrushPropertyKey, new ImageBrush(BitmapFrame.Create(Uri, BitmapCreateOptions.IgnoreImageCache, BitmapCacheOption.None))
|
||||
{
|
||||
Stretch = Stretch
|
||||
});
|
||||
SetValue(HasValuePropertyKey, ValueBoxes.TrueBox);
|
||||
SetCurrentValue(ToolTipProperty, dialog.FileName);
|
||||
RaiseEvent(new RoutedEventArgs(ImageSelectedEvent, this));
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty StretchProperty = DependencyProperty.Register(
|
||||
"Stretch", typeof(Stretch), typeof(ImageSelector), new PropertyMetadata(default(Stretch)));
|
||||
|
||||
public Stretch Stretch
|
||||
else
|
||||
{
|
||||
get => (Stretch) GetValue(StretchProperty);
|
||||
set => SetValue(StretchProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyPropertyKey UriPropertyKey = DependencyProperty.RegisterReadOnly(
|
||||
"Uri", typeof(Uri), typeof(ImageSelector), new PropertyMetadata(default(Uri)));
|
||||
|
||||
public static readonly DependencyProperty UriProperty = UriPropertyKey.DependencyProperty;
|
||||
|
||||
public Uri Uri
|
||||
{
|
||||
get => (Uri) GetValue(UriProperty);
|
||||
set => SetValue(UriProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyPropertyKey PreviewBrushPropertyKey = DependencyProperty.RegisterReadOnly(
|
||||
"PreviewBrush", typeof(Brush), typeof(ImageSelector), new PropertyMetadata(default(Brush)));
|
||||
|
||||
public static readonly DependencyProperty PreviewBrushProperty = PreviewBrushPropertyKey.DependencyProperty;
|
||||
|
||||
public Brush PreviewBrush
|
||||
{
|
||||
get => (Brush) GetValue(PreviewBrushProperty);
|
||||
set => SetValue(PreviewBrushProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
|
||||
"StrokeThickness", typeof(double), typeof(ImageSelector), new FrameworkPropertyMetadata(ValueBoxes.Double1Box, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public double StrokeThickness
|
||||
{
|
||||
get => (double) GetValue(StrokeThicknessProperty);
|
||||
set => SetValue(StrokeThicknessProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty StrokeDashArrayProperty = DependencyProperty.Register(
|
||||
"StrokeDashArray", typeof(DoubleCollection), typeof(ImageSelector), new FrameworkPropertyMetadata(default(DoubleCollection), FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public DoubleCollection StrokeDashArray
|
||||
{
|
||||
get => (DoubleCollection) GetValue(StrokeDashArrayProperty);
|
||||
set => SetValue(StrokeDashArrayProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DefaultExtProperty = DependencyProperty.Register(
|
||||
"DefaultExt", typeof(string), typeof(ImageSelector), new PropertyMetadata(".jpg"));
|
||||
|
||||
public string DefaultExt
|
||||
{
|
||||
get => (string) GetValue(DefaultExtProperty);
|
||||
set => SetValue(DefaultExtProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FilterProperty = DependencyProperty.Register(
|
||||
"Filter", typeof(string), typeof(ImageSelector), new PropertyMetadata("(.jpg)|*.jpg|(.png)|*.png"));
|
||||
|
||||
public string Filter
|
||||
{
|
||||
get => (string) GetValue(FilterProperty);
|
||||
set => SetValue(FilterProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyPropertyKey HasValuePropertyKey = DependencyProperty.RegisterReadOnly(
|
||||
"HasValue", typeof(bool), typeof(ImageSelector), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public static readonly DependencyProperty HasValueProperty = HasValuePropertyKey.DependencyProperty;
|
||||
|
||||
public bool HasValue
|
||||
{
|
||||
get => (bool) GetValue(HasValueProperty);
|
||||
set => SetValue(HasValueProperty, ValueBoxes.BooleanBox(value));
|
||||
SetValue(UriPropertyKey, default(Uri));
|
||||
SetValue(PreviewBrushPropertyKey, default(Brush));
|
||||
SetValue(HasValuePropertyKey, ValueBoxes.FalseBox);
|
||||
SetCurrentValue(ToolTipProperty, default);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty StretchProperty = DependencyProperty.Register(
|
||||
"Stretch", typeof(Stretch), typeof(ImageSelector), new PropertyMetadata(default(Stretch)));
|
||||
|
||||
public Stretch Stretch
|
||||
{
|
||||
get => (Stretch) GetValue(StretchProperty);
|
||||
set => SetValue(StretchProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyPropertyKey UriPropertyKey = DependencyProperty.RegisterReadOnly(
|
||||
"Uri", typeof(Uri), typeof(ImageSelector), new PropertyMetadata(default(Uri)));
|
||||
|
||||
public static readonly DependencyProperty UriProperty = UriPropertyKey.DependencyProperty;
|
||||
|
||||
public Uri Uri
|
||||
{
|
||||
get => (Uri) GetValue(UriProperty);
|
||||
set => SetValue(UriProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyPropertyKey PreviewBrushPropertyKey = DependencyProperty.RegisterReadOnly(
|
||||
"PreviewBrush", typeof(Brush), typeof(ImageSelector), new PropertyMetadata(default(Brush)));
|
||||
|
||||
public static readonly DependencyProperty PreviewBrushProperty = PreviewBrushPropertyKey.DependencyProperty;
|
||||
|
||||
public Brush PreviewBrush
|
||||
{
|
||||
get => (Brush) GetValue(PreviewBrushProperty);
|
||||
set => SetValue(PreviewBrushProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
|
||||
"StrokeThickness", typeof(double), typeof(ImageSelector), new FrameworkPropertyMetadata(ValueBoxes.Double1Box, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public double StrokeThickness
|
||||
{
|
||||
get => (double) GetValue(StrokeThicknessProperty);
|
||||
set => SetValue(StrokeThicknessProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty StrokeDashArrayProperty = DependencyProperty.Register(
|
||||
"StrokeDashArray", typeof(DoubleCollection), typeof(ImageSelector), new FrameworkPropertyMetadata(default(DoubleCollection), FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public DoubleCollection StrokeDashArray
|
||||
{
|
||||
get => (DoubleCollection) GetValue(StrokeDashArrayProperty);
|
||||
set => SetValue(StrokeDashArrayProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DefaultExtProperty = DependencyProperty.Register(
|
||||
"DefaultExt", typeof(string), typeof(ImageSelector), new PropertyMetadata(".jpg"));
|
||||
|
||||
public string DefaultExt
|
||||
{
|
||||
get => (string) GetValue(DefaultExtProperty);
|
||||
set => SetValue(DefaultExtProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FilterProperty = DependencyProperty.Register(
|
||||
"Filter", typeof(string), typeof(ImageSelector), new PropertyMetadata("(.jpg)|*.jpg|(.png)|*.png"));
|
||||
|
||||
public string Filter
|
||||
{
|
||||
get => (string) GetValue(FilterProperty);
|
||||
set => SetValue(FilterProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyPropertyKey HasValuePropertyKey = DependencyProperty.RegisterReadOnly(
|
||||
"HasValue", typeof(bool), typeof(ImageSelector), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public static readonly DependencyProperty HasValueProperty = HasValuePropertyKey.DependencyProperty;
|
||||
|
||||
public bool HasValue
|
||||
{
|
||||
get => (bool) GetValue(HasValueProperty);
|
||||
set => SetValue(HasValueProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
}
|
||||
@@ -9,512 +9,334 @@ using HandyControl.Data;
|
||||
using HandyControl.Interactivity;
|
||||
using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// 数值选择控件
|
||||
/// </summary>
|
||||
[TemplatePart(Name = ElementTextBox, Type = typeof(TextBox))]
|
||||
public class NumericUpDown : Control
|
||||
{
|
||||
/// <summary>
|
||||
/// 数值选择控件
|
||||
/// </summary>
|
||||
[TemplatePart(Name = ElementTextBox, Type = typeof(TextBox))]
|
||||
[TemplatePart(Name = ElementErrorTip, Type = typeof(UIElement))]
|
||||
public class NumericUpDown : Control, IDataInput
|
||||
private const string ElementTextBox = "PART_TextBox";
|
||||
|
||||
private TextBox _textBox;
|
||||
|
||||
public NumericUpDown()
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private const string ElementTextBox = "PART_TextBox";
|
||||
|
||||
private const string ElementErrorTip = "PART_ErrorTip";
|
||||
|
||||
#endregion Constants
|
||||
|
||||
#region Data
|
||||
|
||||
private TextBox _textBox;
|
||||
|
||||
private UIElement _errorTip;
|
||||
|
||||
private bool _updateText;
|
||||
|
||||
#endregion Data
|
||||
|
||||
public NumericUpDown()
|
||||
{
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Prev, (s, e) =>
|
||||
{
|
||||
if (IsReadOnly) return;
|
||||
|
||||
Value += Increment;
|
||||
}));
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Next, (s, e) =>
|
||||
{
|
||||
if (IsReadOnly) return;
|
||||
|
||||
Value -= Increment;
|
||||
}));
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
|
||||
{
|
||||
if (IsReadOnly) return;
|
||||
|
||||
SetCurrentValue(ValueProperty, ValueBoxes.Double0Box);
|
||||
}));
|
||||
|
||||
Loaded += (s, e) => OnApplyTemplate();
|
||||
}
|
||||
|
||||
protected override void OnGotFocus(RoutedEventArgs e)
|
||||
{
|
||||
base.OnGotFocus(e);
|
||||
|
||||
if (_textBox != null)
|
||||
{
|
||||
_textBox?.Focus();
|
||||
_textBox.Select(_textBox.Text.Length, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
if (_textBox != null)
|
||||
{
|
||||
TextCompositionManager.RemovePreviewTextInputHandler(_textBox, PreviewTextInputHandler);
|
||||
_textBox.TextChanged -= TextBox_TextChanged;
|
||||
_textBox.PreviewKeyDown -= TextBox_PreviewKeyDown;
|
||||
_textBox.LostFocus -= TextBox_LostFocus;
|
||||
}
|
||||
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_textBox = GetTemplateChild(ElementTextBox) as TextBox;
|
||||
_errorTip = GetTemplateChild(ElementErrorTip) as UIElement;
|
||||
|
||||
if (_textBox != null)
|
||||
{
|
||||
_textBox.SetBinding(SelectionBrushProperty, new Binding(SelectionBrushProperty.Name) { Source = this });
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
_textBox.SetBinding(SelectionTextBrushProperty, new Binding(SelectionTextBrushProperty.Name) { Source = this });
|
||||
#endif
|
||||
_textBox.SetBinding(SelectionOpacityProperty, new Binding(SelectionOpacityProperty.Name) { Source = this });
|
||||
_textBox.SetBinding(CaretBrushProperty, new Binding(CaretBrushProperty.Name) { Source = this });
|
||||
|
||||
TextCompositionManager.AddPreviewTextInputHandler(_textBox, PreviewTextInputHandler);
|
||||
_textBox.TextChanged += TextBox_TextChanged;
|
||||
_textBox.PreviewKeyDown += TextBox_PreviewKeyDown;
|
||||
_textBox.LostFocus += TextBox_LostFocus;
|
||||
_textBox.Text = CurrentText;
|
||||
}
|
||||
}
|
||||
|
||||
private void TextBox_TextChanged(object sender, TextChangedEventArgs e) => UpdateData();
|
||||
|
||||
private void UpdateData()
|
||||
{
|
||||
if (!VerifyData())
|
||||
{
|
||||
_updateText = true;
|
||||
return;
|
||||
}
|
||||
|
||||
_updateText = false;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(_textBox.Text))
|
||||
{
|
||||
Value = 0;
|
||||
|
||||
SetCurrentValue(ErrorStrProperty, string.Empty);
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.FalseBox);
|
||||
}
|
||||
else if (double.TryParse(_textBox.Text, out var value))
|
||||
{
|
||||
Value = value;
|
||||
|
||||
if (Validation.GetHasError(this))
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.TrueBox);
|
||||
}
|
||||
}
|
||||
|
||||
_updateText = true;
|
||||
}
|
||||
|
||||
private void PreviewTextInputHandler(object sender, TextCompositionEventArgs e) => UpdateData();
|
||||
|
||||
private void TextBox_LostFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (IsError && _errorTip != null) return;
|
||||
_textBox.Text = CurrentText;
|
||||
}
|
||||
|
||||
private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Prev, (s, e) =>
|
||||
{
|
||||
if (IsReadOnly) return;
|
||||
|
||||
if (e.Key == Key.Up)
|
||||
{
|
||||
Value += Increment;
|
||||
}
|
||||
else if (e.Key == Key.Down)
|
||||
{
|
||||
Value -= Increment;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseWheel(MouseWheelEventArgs e)
|
||||
SetCurrentValue(ValueProperty, Value + Increment);
|
||||
}));
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Next, (s, e) =>
|
||||
{
|
||||
base.OnMouseWheel(e);
|
||||
if (IsReadOnly) return;
|
||||
|
||||
if (_textBox.IsFocused && !IsReadOnly)
|
||||
{
|
||||
Value += e.Delta > 0 ? Increment : -Increment;
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private string CurrentText => string.IsNullOrWhiteSpace(ValueFormat)
|
||||
? DecimalPlaces.HasValue
|
||||
? Value.ToString($"#0.{new string('0', DecimalPlaces.Value)}")
|
||||
: Value.ToString()
|
||||
: Value.ToString(ValueFormat);
|
||||
|
||||
protected virtual void OnValueChanged(FunctionEventArgs<double> e) => RaiseEvent(e);
|
||||
|
||||
/// <summary>
|
||||
/// 值改变事件
|
||||
/// </summary>
|
||||
public static readonly RoutedEvent ValueChangedEvent =
|
||||
EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble,
|
||||
typeof(EventHandler<FunctionEventArgs<double>>), typeof(NumericUpDown));
|
||||
|
||||
/// <summary>
|
||||
/// 值改变事件
|
||||
/// </summary>
|
||||
public event EventHandler<FunctionEventArgs<double>> ValueChanged
|
||||
SetCurrentValue(ValueProperty, Value - Increment);
|
||||
}));
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
|
||||
{
|
||||
add => AddHandler(ValueChangedEvent, value);
|
||||
remove => RemoveHandler(ValueChangedEvent, value);
|
||||
}
|
||||
if (IsReadOnly) return;
|
||||
|
||||
/// <summary>
|
||||
/// 当前值
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
|
||||
"Value", typeof(double), typeof(NumericUpDown),
|
||||
new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
OnValueChanged, CoerceValue), ValidateHelper.IsInRangeOfDouble);
|
||||
SetCurrentValue(ValueProperty, ValueBoxes.Double0Box);
|
||||
}));
|
||||
}
|
||||
|
||||
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_textBox = GetTemplateChild(ElementTextBox) as TextBox;
|
||||
|
||||
if (_textBox != null)
|
||||
{
|
||||
var ctl = (NumericUpDown) d;
|
||||
var v = (double) e.NewValue;
|
||||
ctl.SetText();
|
||||
_textBox.SetBinding(SelectionBrushProperty, new Binding(SelectionBrushProperty.Name) { Source = this });
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
_textBox.SetBinding(SelectionTextBrushProperty, new Binding(SelectionTextBrushProperty.Name) { Source = this });
|
||||
#endif
|
||||
_textBox.SetBinding(SelectionOpacityProperty, new Binding(SelectionOpacityProperty.Name) { Source = this });
|
||||
_textBox.SetBinding(CaretBrushProperty, new Binding(CaretBrushProperty.Name) { Source = this });
|
||||
|
||||
ctl.OnValueChanged(new FunctionEventArgs<double>(ValueChangedEvent, ctl)
|
||||
{
|
||||
Info = v
|
||||
});
|
||||
_textBox.PreviewKeyDown += TextBox_PreviewKeyDown;
|
||||
_textBox.Text = CurrentText;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetText()
|
||||
private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (IsReadOnly) return;
|
||||
|
||||
if (e.Key == Key.Up)
|
||||
{
|
||||
if (_updateText && _textBox != null)
|
||||
{
|
||||
_textBox.Text = CurrentText;
|
||||
_textBox.Select(_textBox.Text.Length, 0);
|
||||
}
|
||||
Value += Increment;
|
||||
}
|
||||
|
||||
private static object CoerceValue(DependencyObject d, object basevalue)
|
||||
else if (e.Key == Key.Down)
|
||||
{
|
||||
var ctl = (NumericUpDown) d;
|
||||
var minimum = ctl.Minimum;
|
||||
var num = (double) basevalue;
|
||||
if (num < minimum)
|
||||
{
|
||||
ctl.Value = minimum;
|
||||
return minimum;
|
||||
}
|
||||
var maximum = ctl.Maximum;
|
||||
if (num > maximum)
|
||||
{
|
||||
ctl.Value = maximum;
|
||||
}
|
||||
ctl.SetText();
|
||||
return num > maximum ? maximum : num;
|
||||
Value -= Increment;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前值
|
||||
/// </summary>
|
||||
public double Value
|
||||
protected override void OnMouseWheel(MouseWheelEventArgs e)
|
||||
{
|
||||
base.OnMouseWheel(e);
|
||||
|
||||
if (_textBox.IsFocused && !IsReadOnly)
|
||||
{
|
||||
get => (double) GetValue(ValueProperty);
|
||||
set => SetValue(ValueProperty, value);
|
||||
Value += e.Delta > 0 ? Increment : -Increment;
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最大值
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register(
|
||||
"Maximum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(double.MaxValue, OnMaximumChanged, CoerceMaximum), ValidateHelper.IsInRangeOfDouble);
|
||||
private string CurrentText => string.IsNullOrWhiteSpace(ValueFormat)
|
||||
? DecimalPlaces.HasValue
|
||||
? Value.ToString($"#0.{new string('0', DecimalPlaces.Value)}")
|
||||
: Value.ToString()
|
||||
: Value.ToString(ValueFormat);
|
||||
|
||||
private static void OnMaximumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
protected virtual void OnValueChanged(FunctionEventArgs<double> e) => RaiseEvent(e);
|
||||
|
||||
/// <summary>
|
||||
/// 值改变事件
|
||||
/// </summary>
|
||||
public static readonly RoutedEvent ValueChangedEvent =
|
||||
EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble,
|
||||
typeof(EventHandler<FunctionEventArgs<double>>), typeof(NumericUpDown));
|
||||
|
||||
/// <summary>
|
||||
/// 值改变事件
|
||||
/// </summary>
|
||||
public event EventHandler<FunctionEventArgs<double>> ValueChanged
|
||||
{
|
||||
add => AddHandler(ValueChangedEvent, value);
|
||||
remove => RemoveHandler(ValueChangedEvent, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前值
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
|
||||
"Value", typeof(double), typeof(NumericUpDown),
|
||||
new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
OnValueChanged, CoerceValue), ValidateHelper.IsInRangeOfDouble);
|
||||
|
||||
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (NumericUpDown) d;
|
||||
var v = (double) e.NewValue;
|
||||
ctl.SetText();
|
||||
|
||||
ctl.OnValueChanged(new FunctionEventArgs<double>(ValueChangedEvent, ctl)
|
||||
{
|
||||
var ctl = (NumericUpDown) d;
|
||||
ctl.CoerceValue(MinimumProperty);
|
||||
ctl.CoerceValue(ValueProperty);
|
||||
}
|
||||
Info = v
|
||||
});
|
||||
}
|
||||
|
||||
private static object CoerceMaximum(DependencyObject d, object basevalue)
|
||||
private void SetText()
|
||||
{
|
||||
if (_textBox != null)
|
||||
{
|
||||
var minimum = ((NumericUpDown) d).Minimum;
|
||||
return (double) basevalue < minimum ? minimum : basevalue;
|
||||
_textBox.Text = CurrentText;
|
||||
_textBox.Select(_textBox.Text.Length, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最大值
|
||||
/// </summary>
|
||||
public double Maximum
|
||||
private static object CoerceValue(DependencyObject d, object basevalue)
|
||||
{
|
||||
var ctl = (NumericUpDown) d;
|
||||
var minimum = ctl.Minimum;
|
||||
var num = (double) basevalue;
|
||||
if (num < minimum)
|
||||
{
|
||||
get => (double) GetValue(MaximumProperty);
|
||||
set => SetValue(MaximumProperty, value);
|
||||
ctl.Value = minimum;
|
||||
return minimum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最小值
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register(
|
||||
"Minimum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(double.MinValue, OnMinimumChanged, CoerceMinimum), ValidateHelper.IsInRangeOfDouble);
|
||||
|
||||
private static void OnMinimumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
var maximum = ctl.Maximum;
|
||||
if (num > maximum)
|
||||
{
|
||||
var ctl = (NumericUpDown) d;
|
||||
ctl.CoerceValue(MaximumProperty);
|
||||
ctl.CoerceValue(ValueProperty);
|
||||
ctl.Value = maximum;
|
||||
}
|
||||
ctl.SetText();
|
||||
return num > maximum ? maximum : num;
|
||||
}
|
||||
|
||||
private static object CoerceMinimum(DependencyObject d, object basevalue)
|
||||
{
|
||||
var maximum = ((NumericUpDown) d).Maximum;
|
||||
return (double) basevalue > maximum ? maximum : basevalue;
|
||||
}
|
||||
/// <summary>
|
||||
/// 当前值
|
||||
/// </summary>
|
||||
public double Value
|
||||
{
|
||||
get => (double) GetValue(ValueProperty);
|
||||
set => SetValue(ValueProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最小值
|
||||
/// </summary>
|
||||
public double Minimum
|
||||
{
|
||||
get => (double) GetValue(MinimumProperty);
|
||||
set => SetValue(MinimumProperty, value);
|
||||
}
|
||||
/// <summary>
|
||||
/// 最大值
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register(
|
||||
"Maximum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(double.MaxValue, OnMaximumChanged, CoerceMaximum), ValidateHelper.IsInRangeOfDouble);
|
||||
|
||||
/// <summary>
|
||||
/// 指示每单击一下按钮时增加或减少的数量
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IncrementProperty = DependencyProperty.Register(
|
||||
"Increment", typeof(double), typeof(NumericUpDown), new PropertyMetadata(ValueBoxes.Double1Box));
|
||||
private static void OnMaximumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (NumericUpDown) d;
|
||||
ctl.CoerceValue(MinimumProperty);
|
||||
ctl.CoerceValue(ValueProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 指示每单击一下按钮时增加或减少的数量
|
||||
/// </summary>
|
||||
public double Increment
|
||||
{
|
||||
get => (double) GetValue(IncrementProperty);
|
||||
set => SetValue(IncrementProperty, value);
|
||||
}
|
||||
private static object CoerceMaximum(DependencyObject d, object basevalue)
|
||||
{
|
||||
var minimum = ((NumericUpDown) d).Minimum;
|
||||
return (double) basevalue < minimum ? minimum : basevalue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 指示要显示的小数位数
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty DecimalPlacesProperty = DependencyProperty.Register(
|
||||
"DecimalPlaces", typeof(int?), typeof(NumericUpDown), new PropertyMetadata(default(int?)));
|
||||
/// <summary>
|
||||
/// 最大值
|
||||
/// </summary>
|
||||
public double Maximum
|
||||
{
|
||||
get => (double) GetValue(MaximumProperty);
|
||||
set => SetValue(MaximumProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 指示要显示的小数位数
|
||||
/// </summary>
|
||||
public int? DecimalPlaces
|
||||
{
|
||||
get => (int?) GetValue(DecimalPlacesProperty);
|
||||
set => SetValue(DecimalPlacesProperty, value);
|
||||
}
|
||||
/// <summary>
|
||||
/// 最小值
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register(
|
||||
"Minimum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(double.MinValue, OnMinimumChanged, CoerceMinimum), ValidateHelper.IsInRangeOfDouble);
|
||||
|
||||
/// <summary>
|
||||
/// 指示要显示的数字的格式
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ValueFormatProperty = DependencyProperty.Register(
|
||||
"ValueFormat", typeof(string), typeof(NumericUpDown), new PropertyMetadata(default(string)));
|
||||
private static void OnMinimumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (NumericUpDown) d;
|
||||
ctl.CoerceValue(MaximumProperty);
|
||||
ctl.CoerceValue(ValueProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 指示要显示的数字的格式,这将会覆盖 <see cref="DecimalPlaces"/> 属性
|
||||
/// </summary>
|
||||
public string ValueFormat
|
||||
{
|
||||
get => (string) GetValue(ValueFormatProperty);
|
||||
set => SetValue(ValueFormatProperty, value);
|
||||
}
|
||||
private static object CoerceMinimum(DependencyObject d, object basevalue)
|
||||
{
|
||||
var maximum = ((NumericUpDown) d).Maximum;
|
||||
return (double) basevalue > maximum ? maximum : basevalue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示上下调值按钮
|
||||
/// </summary>
|
||||
internal static readonly DependencyProperty ShowUpDownButtonProperty = DependencyProperty.Register(
|
||||
"ShowUpDownButton", typeof(bool), typeof(NumericUpDown), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
/// <summary>
|
||||
/// 最小值
|
||||
/// </summary>
|
||||
public double Minimum
|
||||
{
|
||||
get => (double) GetValue(MinimumProperty);
|
||||
set => SetValue(MinimumProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示上下调值按钮
|
||||
/// </summary>
|
||||
internal bool ShowUpDownButton
|
||||
{
|
||||
get => (bool) GetValue(ShowUpDownButtonProperty);
|
||||
set => SetValue(ShowUpDownButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
/// <summary>
|
||||
/// 指示每单击一下按钮时增加或减少的数量
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IncrementProperty = DependencyProperty.Register(
|
||||
"Increment", typeof(double), typeof(NumericUpDown), new PropertyMetadata(ValueBoxes.Double1Box));
|
||||
|
||||
/// <summary>
|
||||
/// 数据是否错误
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register(
|
||||
"IsError", typeof(bool), typeof(NumericUpDown), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
/// <summary>
|
||||
/// 指示每单击一下按钮时增加或减少的数量
|
||||
/// </summary>
|
||||
public double Increment
|
||||
{
|
||||
get => (double) GetValue(IncrementProperty);
|
||||
set => SetValue(IncrementProperty, value);
|
||||
}
|
||||
|
||||
public bool IsError
|
||||
{
|
||||
get => (bool) GetValue(IsErrorProperty);
|
||||
set => SetValue(IsErrorProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
/// <summary>
|
||||
/// 指示要显示的小数位数
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty DecimalPlacesProperty = DependencyProperty.Register(
|
||||
"DecimalPlaces", typeof(int?), typeof(NumericUpDown), new PropertyMetadata(default(int?)));
|
||||
|
||||
/// <summary>
|
||||
/// 错误提示
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ErrorStrProperty = DependencyProperty.Register(
|
||||
"ErrorStr", typeof(string), typeof(NumericUpDown), new PropertyMetadata(default(string)));
|
||||
/// <summary>
|
||||
/// 指示要显示的小数位数
|
||||
/// </summary>
|
||||
public int? DecimalPlaces
|
||||
{
|
||||
get => (int?) GetValue(DecimalPlacesProperty);
|
||||
set => SetValue(DecimalPlacesProperty, value);
|
||||
}
|
||||
|
||||
public string ErrorStr
|
||||
{
|
||||
get => (string) GetValue(ErrorStrProperty);
|
||||
set => SetValue(ErrorStrProperty, value);
|
||||
}
|
||||
/// <summary>
|
||||
/// 指示要显示的数字的格式
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ValueFormatProperty = DependencyProperty.Register(
|
||||
"ValueFormat", typeof(string), typeof(NumericUpDown), new PropertyMetadata(default(string)));
|
||||
|
||||
public static readonly DependencyPropertyKey TextTypePropertyKey =
|
||||
DependencyProperty.RegisterReadOnly("TextType", typeof(TextType), typeof(NumericUpDown),
|
||||
new PropertyMetadata(default(TextType)));
|
||||
/// <summary>
|
||||
/// 指示要显示的数字的格式,这将会覆盖 <see cref="DecimalPlaces"/> 属性
|
||||
/// </summary>
|
||||
public string ValueFormat
|
||||
{
|
||||
get => (string) GetValue(ValueFormatProperty);
|
||||
set => SetValue(ValueFormatProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TextTypeProperty = TextTypePropertyKey.DependencyProperty;
|
||||
/// <summary>
|
||||
/// 是否显示上下调值按钮
|
||||
/// </summary>
|
||||
internal static readonly DependencyProperty ShowUpDownButtonProperty = DependencyProperty.Register(
|
||||
"ShowUpDownButton", typeof(bool), typeof(NumericUpDown), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
|
||||
public TextType TextType
|
||||
{
|
||||
get => (TextType) GetValue(TextTypeProperty);
|
||||
set => SetValue(TextTypeProperty, value);
|
||||
}
|
||||
/// <summary>
|
||||
/// 是否显示上下调值按钮
|
||||
/// </summary>
|
||||
internal bool ShowUpDownButton
|
||||
{
|
||||
get => (bool) GetValue(ShowUpDownButtonProperty);
|
||||
set => SetValue(ShowUpDownButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示清除按钮
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ShowClearButtonProperty = DependencyProperty.Register(
|
||||
"ShowClearButton", typeof(bool), typeof(NumericUpDown), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
/// <summary>
|
||||
/// 标识 IsReadOnly 依赖属性。
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register(
|
||||
"IsReadOnly", typeof(bool), typeof(NumericUpDown), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool ShowClearButton
|
||||
{
|
||||
get => (bool) GetValue(ShowClearButtonProperty);
|
||||
set => SetValue(ShowClearButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取或设置一个值,该值指示NumericUpDown是否只读。
|
||||
/// </summary>
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get => (bool) GetValue(IsReadOnlyProperty);
|
||||
set => SetValue(IsReadOnlyProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标识 IsReadOnly 依赖属性。
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register(
|
||||
"IsReadOnly", typeof(bool), typeof(NumericUpDown), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
public static readonly DependencyProperty SelectionBrushProperty =
|
||||
TextBoxBase.SelectionBrushProperty.AddOwner(typeof(NumericUpDown));
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置一个值,该值指示NumericUpDown是否只读。
|
||||
/// </summary>
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get => (bool) GetValue(IsReadOnlyProperty);
|
||||
set => SetValue(IsReadOnlyProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectionBrushProperty =
|
||||
TextBoxBase.SelectionBrushProperty.AddOwner(typeof(NumericUpDown));
|
||||
|
||||
public Brush SelectionBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionBrushProperty);
|
||||
set => SetValue(SelectionBrushProperty, value);
|
||||
}
|
||||
public Brush SelectionBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionBrushProperty);
|
||||
set => SetValue(SelectionBrushProperty, value);
|
||||
}
|
||||
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
|
||||
public static readonly DependencyProperty SelectionTextBrushProperty =
|
||||
TextBoxBase.SelectionTextBrushProperty.AddOwner(typeof(NumericUpDown));
|
||||
public static readonly DependencyProperty SelectionTextBrushProperty =
|
||||
TextBoxBase.SelectionTextBrushProperty.AddOwner(typeof(NumericUpDown));
|
||||
|
||||
public Brush SelectionTextBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionTextBrushProperty);
|
||||
set => SetValue(SelectionTextBrushProperty, value);
|
||||
}
|
||||
public Brush SelectionTextBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionTextBrushProperty);
|
||||
set => SetValue(SelectionTextBrushProperty, value);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public static readonly DependencyProperty SelectionOpacityProperty =
|
||||
TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(NumericUpDown));
|
||||
public static readonly DependencyProperty SelectionOpacityProperty =
|
||||
TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(NumericUpDown));
|
||||
|
||||
public double SelectionOpacity
|
||||
{
|
||||
get => (double) GetValue(SelectionOpacityProperty);
|
||||
set => SetValue(SelectionOpacityProperty, value);
|
||||
}
|
||||
public double SelectionOpacity
|
||||
{
|
||||
get => (double) GetValue(SelectionOpacityProperty);
|
||||
set => SetValue(SelectionOpacityProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CaretBrushProperty =
|
||||
TextBoxBase.CaretBrushProperty.AddOwner(typeof(NumericUpDown));
|
||||
public static readonly DependencyProperty CaretBrushProperty =
|
||||
TextBoxBase.CaretBrushProperty.AddOwner(typeof(NumericUpDown));
|
||||
|
||||
public Brush CaretBrush
|
||||
{
|
||||
get => (Brush) GetValue(CaretBrushProperty);
|
||||
set => SetValue(CaretBrushProperty, value);
|
||||
}
|
||||
|
||||
public Func<string, OperationResult<bool>> VerifyFunc { get; set; }
|
||||
|
||||
public virtual bool VerifyData()
|
||||
{
|
||||
OperationResult<bool> result;
|
||||
|
||||
if (VerifyFunc != null)
|
||||
{
|
||||
result = VerifyFunc.Invoke(_textBox.Text);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_textBox.Text))
|
||||
{
|
||||
if (double.TryParse(_textBox.Text, out var value))
|
||||
{
|
||||
if (value < Minimum || value > Maximum)
|
||||
{
|
||||
result = OperationResult.Failed(Properties.Langs.Lang.OutOfRange);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = OperationResult.Failed(Properties.Langs.Lang.FormatError);
|
||||
}
|
||||
}
|
||||
else if (InfoElement.GetNecessary(this))
|
||||
{
|
||||
result = OperationResult.Failed(Properties.Langs.Lang.IsNecessary);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
}
|
||||
|
||||
SetCurrentValue(ErrorStrProperty, result.Message);
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.BooleanBox(!result.Data));
|
||||
return result.Data;
|
||||
}
|
||||
public Brush CaretBrush
|
||||
{
|
||||
get => (Brush) GetValue(CaretBrushProperty);
|
||||
set => SetValue(CaretBrushProperty, value);
|
||||
}
|
||||
}
|
||||
@@ -12,383 +12,382 @@ using HandyControl.Data;
|
||||
using HandyControl.Interactivity;
|
||||
using HandyControl.Properties.Langs;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
[TemplatePart(Name = ElementPasswordBox, Type = typeof(System.Windows.Controls.PasswordBox))]
|
||||
[TemplatePart(Name = ElementTextBox, Type = typeof(System.Windows.Controls.TextBox))]
|
||||
public class PasswordBox : Control, IDataInput
|
||||
{
|
||||
[TemplatePart(Name = ElementPasswordBox, Type = typeof(System.Windows.Controls.PasswordBox))]
|
||||
[TemplatePart(Name = ElementTextBox, Type = typeof(System.Windows.Controls.TextBox))]
|
||||
public class PasswordBox : Control, IDataInput
|
||||
private const string ElementPasswordBox = "PART_PasswordBox";
|
||||
|
||||
private const string ElementTextBox = "PART_TextBox";
|
||||
|
||||
private SecureString _password;
|
||||
|
||||
private System.Windows.Controls.TextBox _textBox;
|
||||
|
||||
/// <summary>
|
||||
/// 掩码字符
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PasswordCharProperty =
|
||||
System.Windows.Controls.PasswordBox.PasswordCharProperty.AddOwner(typeof(PasswordBox),
|
||||
new FrameworkPropertyMetadata('●'));
|
||||
|
||||
public char PasswordChar
|
||||
{
|
||||
private const string ElementPasswordBox = "PART_PasswordBox";
|
||||
get => (char) GetValue(PasswordCharProperty);
|
||||
set => SetValue(PasswordCharProperty, value);
|
||||
}
|
||||
|
||||
private const string ElementTextBox = "PART_TextBox";
|
||||
/// <summary>
|
||||
/// 数据是否错误
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register(
|
||||
"IsError", typeof(bool), typeof(PasswordBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
private SecureString _password;
|
||||
public bool IsError
|
||||
{
|
||||
get => (bool) GetValue(IsErrorProperty);
|
||||
set => SetValue(IsErrorProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
private System.Windows.Controls.TextBox _textBox;
|
||||
/// <summary>
|
||||
/// 错误提示
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ErrorStrProperty = DependencyProperty.Register(
|
||||
"ErrorStr", typeof(string), typeof(PasswordBox), new PropertyMetadata(default(string)));
|
||||
|
||||
/// <summary>
|
||||
/// 掩码字符
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PasswordCharProperty =
|
||||
System.Windows.Controls.PasswordBox.PasswordCharProperty.AddOwner(typeof(PasswordBox),
|
||||
new FrameworkPropertyMetadata('●'));
|
||||
public string ErrorStr
|
||||
{
|
||||
get => (string) GetValue(ErrorStrProperty);
|
||||
set => SetValue(ErrorStrProperty, value);
|
||||
}
|
||||
|
||||
public char PasswordChar
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TextTypeProperty = DependencyProperty.Register(
|
||||
"TextType", typeof(TextType), typeof(PasswordBox), new PropertyMetadata(default(TextType)));
|
||||
|
||||
public TextType TextType
|
||||
{
|
||||
get => (TextType) GetValue(TextTypeProperty);
|
||||
set => SetValue(TextTypeProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示清除按钮
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ShowClearButtonProperty = DependencyProperty.Register(
|
||||
"ShowClearButton", typeof(bool), typeof(PasswordBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool ShowClearButton
|
||||
{
|
||||
get => (bool) GetValue(ShowClearButtonProperty);
|
||||
set => SetValue(ShowClearButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowEyeButtonProperty = DependencyProperty.Register(
|
||||
"ShowEyeButton", typeof(bool), typeof(PasswordBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool ShowEyeButton
|
||||
{
|
||||
get => (bool) GetValue(ShowEyeButtonProperty);
|
||||
set => SetValue(ShowEyeButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowPasswordProperty = DependencyProperty.Register(
|
||||
"ShowPassword", typeof(bool), typeof(PasswordBox),
|
||||
new PropertyMetadata(ValueBoxes.FalseBox, OnShowPasswordChanged));
|
||||
|
||||
public bool ShowPassword
|
||||
{
|
||||
get => (bool) GetValue(ShowPasswordProperty);
|
||||
set => SetValue(ShowPasswordProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsSafeEnabledProperty = DependencyProperty.Register(
|
||||
"IsSafeEnabled", typeof(bool), typeof(PasswordBox), new PropertyMetadata(ValueBoxes.TrueBox, OnIsSafeEnabledChanged));
|
||||
|
||||
private static void OnIsSafeEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var p = (PasswordBox) d;
|
||||
p.SetCurrentValue(UnsafePasswordProperty, !(bool) e.NewValue ? p.Password : string.Empty);
|
||||
}
|
||||
|
||||
public bool IsSafeEnabled
|
||||
{
|
||||
get => (bool) GetValue(IsSafeEnabledProperty);
|
||||
set => SetValue(IsSafeEnabledProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty UnsafePasswordProperty = DependencyProperty.Register(
|
||||
"UnsafePassword", typeof(string), typeof(PasswordBox), new FrameworkPropertyMetadata(default(string),
|
||||
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnUnsafePasswordChanged));
|
||||
|
||||
private static void OnUnsafePasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var p = (PasswordBox) d;
|
||||
if (!p.IsSafeEnabled)
|
||||
{
|
||||
get => (char) GetValue(PasswordCharProperty);
|
||||
set => SetValue(PasswordCharProperty, value);
|
||||
p.Password = e.NewValue != null ? e.NewValue.ToString() : string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据是否错误
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register(
|
||||
"IsError", typeof(bool), typeof(PasswordBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
public string UnsafePassword
|
||||
{
|
||||
get => (string) GetValue(UnsafePasswordProperty);
|
||||
set => SetValue(UnsafePasswordProperty, value);
|
||||
}
|
||||
|
||||
public bool IsError
|
||||
{
|
||||
get => (bool) GetValue(IsErrorProperty);
|
||||
set => SetValue(IsErrorProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
public static readonly DependencyProperty MaxLengthProperty =
|
||||
System.Windows.Controls.TextBox.MaxLengthProperty.AddOwner(typeof(PasswordBox));
|
||||
|
||||
/// <summary>
|
||||
/// 错误提示
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ErrorStrProperty = DependencyProperty.Register(
|
||||
"ErrorStr", typeof(string), typeof(PasswordBox), new PropertyMetadata(default(string)));
|
||||
public int MaxLength
|
||||
{
|
||||
get => (int) GetValue(MaxLengthProperty);
|
||||
set => SetValue(MaxLengthProperty, value);
|
||||
}
|
||||
|
||||
public string ErrorStr
|
||||
{
|
||||
get => (string) GetValue(ErrorStrProperty);
|
||||
set => SetValue(ErrorStrProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty SelectionBrushProperty =
|
||||
TextBoxBase.SelectionBrushProperty.AddOwner(typeof(PasswordBox));
|
||||
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TextTypeProperty = DependencyProperty.Register(
|
||||
"TextType", typeof(TextType), typeof(PasswordBox), new PropertyMetadata(default(TextType)));
|
||||
|
||||
public TextType TextType
|
||||
{
|
||||
get => (TextType) GetValue(TextTypeProperty);
|
||||
set => SetValue(TextTypeProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示清除按钮
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ShowClearButtonProperty = DependencyProperty.Register(
|
||||
"ShowClearButton", typeof(bool), typeof(PasswordBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool ShowClearButton
|
||||
{
|
||||
get => (bool) GetValue(ShowClearButtonProperty);
|
||||
set => SetValue(ShowClearButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowEyeButtonProperty = DependencyProperty.Register(
|
||||
"ShowEyeButton", typeof(bool), typeof(PasswordBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool ShowEyeButton
|
||||
{
|
||||
get => (bool) GetValue(ShowEyeButtonProperty);
|
||||
set => SetValue(ShowEyeButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowPasswordProperty = DependencyProperty.Register(
|
||||
"ShowPassword", typeof(bool), typeof(PasswordBox),
|
||||
new PropertyMetadata(ValueBoxes.FalseBox, OnShowPasswordChanged));
|
||||
|
||||
public bool ShowPassword
|
||||
{
|
||||
get => (bool) GetValue(ShowPasswordProperty);
|
||||
set => SetValue(ShowPasswordProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsSafeEnabledProperty = DependencyProperty.Register(
|
||||
"IsSafeEnabled", typeof(bool), typeof(PasswordBox), new PropertyMetadata(ValueBoxes.TrueBox, OnIsSafeEnabledChanged));
|
||||
|
||||
private static void OnIsSafeEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var p = (PasswordBox) d;
|
||||
p.SetCurrentValue(UnsafePasswordProperty, !(bool) e.NewValue ? p.Password : string.Empty);
|
||||
}
|
||||
|
||||
public bool IsSafeEnabled
|
||||
{
|
||||
get => (bool) GetValue(IsSafeEnabledProperty);
|
||||
set => SetValue(IsSafeEnabledProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty UnsafePasswordProperty = DependencyProperty.Register(
|
||||
"UnsafePassword", typeof(string), typeof(PasswordBox), new FrameworkPropertyMetadata(default(string),
|
||||
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnUnsafePasswordChanged));
|
||||
|
||||
private static void OnUnsafePasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var p = (PasswordBox) d;
|
||||
if (!p.IsSafeEnabled)
|
||||
{
|
||||
p.Password = e.NewValue != null ? e.NewValue.ToString() : string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public string UnsafePassword
|
||||
{
|
||||
get => (string) GetValue(UnsafePasswordProperty);
|
||||
set => SetValue(UnsafePasswordProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MaxLengthProperty =
|
||||
System.Windows.Controls.TextBox.MaxLengthProperty.AddOwner(typeof(PasswordBox));
|
||||
|
||||
public int MaxLength
|
||||
{
|
||||
get => (int) GetValue(MaxLengthProperty);
|
||||
set => SetValue(MaxLengthProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectionBrushProperty =
|
||||
TextBoxBase.SelectionBrushProperty.AddOwner(typeof(PasswordBox));
|
||||
|
||||
public Brush SelectionBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionBrushProperty);
|
||||
set => SetValue(SelectionBrushProperty, value);
|
||||
}
|
||||
public Brush SelectionBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionBrushProperty);
|
||||
set => SetValue(SelectionBrushProperty, value);
|
||||
}
|
||||
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
|
||||
public static readonly DependencyProperty SelectionTextBrushProperty =
|
||||
TextBoxBase.SelectionTextBrushProperty.AddOwner(typeof(PasswordBox));
|
||||
public static readonly DependencyProperty SelectionTextBrushProperty =
|
||||
TextBoxBase.SelectionTextBrushProperty.AddOwner(typeof(PasswordBox));
|
||||
|
||||
public Brush SelectionTextBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionTextBrushProperty);
|
||||
set => SetValue(SelectionTextBrushProperty, value);
|
||||
}
|
||||
public Brush SelectionTextBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionTextBrushProperty);
|
||||
set => SetValue(SelectionTextBrushProperty, value);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public static readonly DependencyProperty SelectionOpacityProperty =
|
||||
TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(PasswordBox));
|
||||
public static readonly DependencyProperty SelectionOpacityProperty =
|
||||
TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(PasswordBox));
|
||||
|
||||
public double SelectionOpacity
|
||||
{
|
||||
get => (double) GetValue(SelectionOpacityProperty);
|
||||
set => SetValue(SelectionOpacityProperty, value);
|
||||
}
|
||||
public double SelectionOpacity
|
||||
{
|
||||
get => (double) GetValue(SelectionOpacityProperty);
|
||||
set => SetValue(SelectionOpacityProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CaretBrushProperty =
|
||||
TextBoxBase.CaretBrushProperty.AddOwner(typeof(PasswordBox));
|
||||
public static readonly DependencyProperty CaretBrushProperty =
|
||||
TextBoxBase.CaretBrushProperty.AddOwner(typeof(PasswordBox));
|
||||
|
||||
public Brush CaretBrush
|
||||
{
|
||||
get => (Brush) GetValue(CaretBrushProperty);
|
||||
set => SetValue(CaretBrushProperty, value);
|
||||
}
|
||||
public Brush CaretBrush
|
||||
{
|
||||
get => (Brush) GetValue(CaretBrushProperty);
|
||||
set => SetValue(CaretBrushProperty, value);
|
||||
}
|
||||
|
||||
#if !NET40
|
||||
|
||||
public static readonly DependencyProperty IsSelectionActiveProperty =
|
||||
TextBoxBase.IsSelectionActiveProperty.AddOwner(typeof(PasswordBox));
|
||||
public static readonly DependencyProperty IsSelectionActiveProperty =
|
||||
TextBoxBase.IsSelectionActiveProperty.AddOwner(typeof(PasswordBox));
|
||||
|
||||
public bool IsSelectionActive => ActualPasswordBox != null && (bool) ActualPasswordBox.GetValue(IsSelectionActiveProperty);
|
||||
public bool IsSelectionActive => ActualPasswordBox != null && (bool) ActualPasswordBox.GetValue(IsSelectionActiveProperty);
|
||||
|
||||
#endif
|
||||
|
||||
public PasswordBox() => CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) => Clear()));
|
||||
public PasswordBox() => CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) => Clear()));
|
||||
|
||||
public System.Windows.Controls.PasswordBox ActualPasswordBox { get; set; }
|
||||
public System.Windows.Controls.PasswordBox ActualPasswordBox { get; set; }
|
||||
|
||||
[DefaultValue("")]
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public string Password
|
||||
[DefaultValue("")]
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public string Password
|
||||
{
|
||||
get
|
||||
{
|
||||
get
|
||||
if (ShowEyeButton && ShowPassword)
|
||||
{
|
||||
if (ShowEyeButton && ShowPassword)
|
||||
{
|
||||
return _textBox.Text;
|
||||
}
|
||||
return ActualPasswordBox?.Password;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (ActualPasswordBox == null)
|
||||
{
|
||||
_password = new SecureString();
|
||||
value ??= string.Empty;
|
||||
foreach (var item in value)
|
||||
_password.AppendChar(item);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (Equals(ActualPasswordBox.Password, value)) return;
|
||||
ActualPasswordBox.Password = value;
|
||||
return _textBox.Text;
|
||||
}
|
||||
return ActualPasswordBox?.Password;
|
||||
}
|
||||
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public SecureString SecurePassword => ActualPasswordBox?.SecurePassword;
|
||||
|
||||
public Func<string, OperationResult<bool>> VerifyFunc { get; set; }
|
||||
|
||||
public virtual bool VerifyData()
|
||||
set
|
||||
{
|
||||
OperationResult<bool> result;
|
||||
if (ActualPasswordBox == null)
|
||||
{
|
||||
_password = new SecureString();
|
||||
value ??= string.Empty;
|
||||
foreach (var item in value)
|
||||
_password.AppendChar(item);
|
||||
|
||||
if (VerifyFunc != null)
|
||||
{
|
||||
result = VerifyFunc.Invoke(ShowEyeButton && ShowPassword
|
||||
? _textBox.Text
|
||||
: ActualPasswordBox.Password);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ShowEyeButton && ShowPassword
|
||||
|
||||
if (Equals(ActualPasswordBox.Password, value)) return;
|
||||
ActualPasswordBox.Password = value;
|
||||
}
|
||||
}
|
||||
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public SecureString SecurePassword => ActualPasswordBox?.SecurePassword;
|
||||
|
||||
public Func<string, OperationResult<bool>> VerifyFunc { get; set; }
|
||||
|
||||
public virtual bool VerifyData()
|
||||
{
|
||||
OperationResult<bool> result;
|
||||
|
||||
if (VerifyFunc != null)
|
||||
{
|
||||
result = VerifyFunc.Invoke(ShowEyeButton && ShowPassword
|
||||
? _textBox.Text
|
||||
: ActualPasswordBox.Password);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ShowEyeButton && ShowPassword
|
||||
? _textBox.Text
|
||||
: ActualPasswordBox.Password))
|
||||
result = OperationResult.Success();
|
||||
else if (InfoElement.GetNecessary(this))
|
||||
result = OperationResult.Failed(Lang.IsNecessary);
|
||||
else
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
result = OperationResult.Success();
|
||||
else if (InfoElement.GetNecessary(this))
|
||||
result = OperationResult.Failed(Lang.IsNecessary);
|
||||
else
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
|
||||
var isError = !result.Data;
|
||||
var isError = !result.Data;
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.TrueBox);
|
||||
SetCurrentValue(ErrorStrProperty, result.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.TrueBox);
|
||||
SetCurrentValue(ErrorStrProperty, result.Message);
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.FalseBox);
|
||||
SetCurrentValue(ErrorStrProperty, default(string));
|
||||
}
|
||||
}
|
||||
return !isError;
|
||||
}
|
||||
|
||||
private static void OnShowPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (PasswordBox) d;
|
||||
if (!ctl.ShowEyeButton) return;
|
||||
if ((bool) e.NewValue)
|
||||
{
|
||||
ctl._textBox.Text = ctl.ActualPasswordBox.Password;
|
||||
ctl._textBox.Select(string.IsNullOrEmpty(ctl._textBox.Text) ? 0 : ctl._textBox.Text.Length, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctl.ActualPasswordBox.Password = ctl._textBox.Text;
|
||||
ctl._textBox.Clear();
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.FalseBox);
|
||||
SetCurrentValue(ErrorStrProperty, default(string));
|
||||
}
|
||||
}
|
||||
return !isError;
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
private static void OnShowPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (PasswordBox) d;
|
||||
if (!ctl.ShowEyeButton) return;
|
||||
if ((bool) e.NewValue)
|
||||
{
|
||||
if (ActualPasswordBox != null)
|
||||
ActualPasswordBox.PasswordChanged -= PasswordBox_PasswordChanged;
|
||||
ctl._textBox.Text = ctl.ActualPasswordBox.Password;
|
||||
ctl._textBox.Select(string.IsNullOrEmpty(ctl._textBox.Text) ? 0 : ctl._textBox.Text.Length, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctl.ActualPasswordBox.Password = ctl._textBox.Text;
|
||||
ctl._textBox.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (_textBox != null)
|
||||
_textBox.TextChanged -= TextBox_TextChanged;
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
if (ActualPasswordBox != null)
|
||||
ActualPasswordBox.PasswordChanged -= PasswordBox_PasswordChanged;
|
||||
|
||||
base.OnApplyTemplate();
|
||||
if (_textBox != null)
|
||||
_textBox.TextChanged -= TextBox_TextChanged;
|
||||
|
||||
ActualPasswordBox = GetTemplateChild(ElementPasswordBox) as System.Windows.Controls.PasswordBox;
|
||||
_textBox = GetTemplateChild(ElementTextBox) as System.Windows.Controls.TextBox;
|
||||
if (ActualPasswordBox != null)
|
||||
{
|
||||
ActualPasswordBox.PasswordChanged += PasswordBox_PasswordChanged;
|
||||
ActualPasswordBox.SetBinding(System.Windows.Controls.PasswordBox.MaxLengthProperty, new Binding(MaxLengthProperty.Name) { Source = this });
|
||||
ActualPasswordBox.SetBinding(System.Windows.Controls.PasswordBox.SelectionBrushProperty, new Binding(SelectionBrushProperty.Name) { Source = this });
|
||||
base.OnApplyTemplate();
|
||||
|
||||
ActualPasswordBox = GetTemplateChild(ElementPasswordBox) as System.Windows.Controls.PasswordBox;
|
||||
_textBox = GetTemplateChild(ElementTextBox) as System.Windows.Controls.TextBox;
|
||||
if (ActualPasswordBox != null)
|
||||
{
|
||||
ActualPasswordBox.PasswordChanged += PasswordBox_PasswordChanged;
|
||||
ActualPasswordBox.SetBinding(System.Windows.Controls.PasswordBox.MaxLengthProperty, new Binding(MaxLengthProperty.Name) { Source = this });
|
||||
ActualPasswordBox.SetBinding(System.Windows.Controls.PasswordBox.SelectionBrushProperty, new Binding(SelectionBrushProperty.Name) { Source = this });
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
ActualPasswordBox.SetBinding(System.Windows.Controls.PasswordBox.SelectionTextBrushProperty, new Binding(SelectionTextBrushProperty.Name) { Source = this });
|
||||
ActualPasswordBox.SetBinding(System.Windows.Controls.PasswordBox.SelectionTextBrushProperty, new Binding(SelectionTextBrushProperty.Name) { Source = this });
|
||||
#endif
|
||||
ActualPasswordBox.SetBinding(System.Windows.Controls.PasswordBox.SelectionOpacityProperty, new Binding(SelectionOpacityProperty.Name) { Source = this });
|
||||
ActualPasswordBox.SetBinding(System.Windows.Controls.PasswordBox.CaretBrushProperty, new Binding(CaretBrushProperty.Name) { Source = this });
|
||||
ActualPasswordBox.SetBinding(System.Windows.Controls.PasswordBox.SelectionOpacityProperty, new Binding(SelectionOpacityProperty.Name) { Source = this });
|
||||
ActualPasswordBox.SetBinding(System.Windows.Controls.PasswordBox.CaretBrushProperty, new Binding(CaretBrushProperty.Name) { Source = this });
|
||||
|
||||
if (_password is { Length: > 0 })
|
||||
{
|
||||
var valuePtr = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
valuePtr = Marshal.SecureStringToGlobalAllocUnicode(_password);
|
||||
ActualPasswordBox.Password = Marshal.PtrToStringUni(valuePtr) ?? throw new InvalidOperationException();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
|
||||
_password.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_textBox != null)
|
||||
if (_password is { Length: > 0 })
|
||||
{
|
||||
_textBox.TextChanged += TextBox_TextChanged;
|
||||
var valuePtr = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
valuePtr = Marshal.SecureStringToGlobalAllocUnicode(_password);
|
||||
ActualPasswordBox.Password = Marshal.PtrToStringUni(valuePtr) ?? throw new InvalidOperationException();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
|
||||
_password.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Paste()
|
||||
if (_textBox != null)
|
||||
{
|
||||
ActualPasswordBox.Paste();
|
||||
if (ShowEyeButton && ShowPassword)
|
||||
_textBox.TextChanged += TextBox_TextChanged;
|
||||
}
|
||||
}
|
||||
|
||||
public void Paste()
|
||||
{
|
||||
ActualPasswordBox.Paste();
|
||||
if (ShowEyeButton && ShowPassword)
|
||||
{
|
||||
_textBox.Text = ActualPasswordBox.Password;
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectAll()
|
||||
{
|
||||
ActualPasswordBox.SelectAll();
|
||||
if (ShowEyeButton && ShowPassword)
|
||||
{
|
||||
_textBox.SelectAll();
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
ActualPasswordBox.Clear();
|
||||
_textBox.Clear();
|
||||
}
|
||||
|
||||
private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!IsSafeEnabled)
|
||||
{
|
||||
SetCurrentValue(UnsafePasswordProperty, ActualPasswordBox.Password);
|
||||
|
||||
if (ShowPassword)
|
||||
{
|
||||
_textBox.Text = ActualPasswordBox.Password;
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectAll()
|
||||
VerifyData();
|
||||
}
|
||||
|
||||
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (!IsSafeEnabled && ShowPassword)
|
||||
{
|
||||
ActualPasswordBox.SelectAll();
|
||||
if (ShowEyeButton && ShowPassword)
|
||||
{
|
||||
_textBox.SelectAll();
|
||||
}
|
||||
Password = _textBox.Text;
|
||||
SetCurrentValue(UnsafePasswordProperty, Password);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
ActualPasswordBox.Clear();
|
||||
_textBox.Clear();
|
||||
}
|
||||
|
||||
private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!IsSafeEnabled)
|
||||
{
|
||||
SetCurrentValue(UnsafePasswordProperty, ActualPasswordBox.Password);
|
||||
|
||||
if (ShowPassword)
|
||||
{
|
||||
_textBox.Text = ActualPasswordBox.Password;
|
||||
}
|
||||
}
|
||||
|
||||
VerifyData();
|
||||
}
|
||||
|
||||
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (!IsSafeEnabled && ShowPassword)
|
||||
{
|
||||
Password = _textBox.Text;
|
||||
SetCurrentValue(UnsafePasswordProperty, Password);
|
||||
}
|
||||
|
||||
VerifyData();
|
||||
}
|
||||
VerifyData();
|
||||
}
|
||||
}
|
||||
@@ -13,398 +13,397 @@ using HandyControl.Data;
|
||||
using HandyControl.Tools;
|
||||
using HandyControl.Tools.Extension;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
[TemplatePart(Name = ElementPanel, Type = typeof(Panel))]
|
||||
public class PinBox : Control
|
||||
{
|
||||
[TemplatePart(Name = ElementPanel, Type = typeof(Panel))]
|
||||
public class PinBox : Control
|
||||
private const string ElementPanel = "PART_Panel";
|
||||
|
||||
private static readonly object MinLength = 4;
|
||||
|
||||
private Panel _panel;
|
||||
|
||||
private int _inputIndex;
|
||||
|
||||
private bool _changed;
|
||||
|
||||
private bool _isInternalAction;
|
||||
|
||||
private List<SecureString> _passwordList;
|
||||
|
||||
private RoutedEventHandler _passwordBoxsGotFocusEventHandler;
|
||||
|
||||
private RoutedEventHandler _passwordBoxsPasswordChangedEventHandler;
|
||||
|
||||
public PinBox()
|
||||
{
|
||||
private const string ElementPanel = "PART_Panel";
|
||||
Loaded += PinBox_Loaded;
|
||||
Unloaded += PinBox_Unloaded;
|
||||
}
|
||||
|
||||
private static readonly object MinLength = 4;
|
||||
private void PinBox_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
RemoveHandler(System.Windows.Controls.PasswordBox.PasswordChangedEvent, _passwordBoxsPasswordChangedEventHandler);
|
||||
RemoveHandler(GotFocusEvent, _passwordBoxsGotFocusEventHandler);
|
||||
|
||||
private Panel _panel;
|
||||
Loaded -= PinBox_Loaded;
|
||||
Unloaded -= PinBox_Unloaded;
|
||||
}
|
||||
|
||||
private int _inputIndex;
|
||||
private void PinBox_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_passwordBoxsPasswordChangedEventHandler = PasswordBoxsPasswordChanged;
|
||||
AddHandler(System.Windows.Controls.PasswordBox.PasswordChangedEvent, _passwordBoxsPasswordChangedEventHandler);
|
||||
|
||||
private bool _changed;
|
||||
_passwordBoxsGotFocusEventHandler = PasswordBoxsGotFocus;
|
||||
AddHandler(GotFocusEvent, _passwordBoxsGotFocusEventHandler);
|
||||
|
||||
private bool _isInternalAction;
|
||||
FocusPasswordBox();
|
||||
}
|
||||
|
||||
private List<SecureString> _passwordList;
|
||||
|
||||
private RoutedEventHandler _passwordBoxsGotFocusEventHandler;
|
||||
|
||||
private RoutedEventHandler _passwordBoxsPasswordChangedEventHandler;
|
||||
|
||||
public PinBox()
|
||||
private void FocusPasswordBox()
|
||||
{
|
||||
if (!IsFocused)
|
||||
{
|
||||
Loaded += PinBox_Loaded;
|
||||
Unloaded += PinBox_Unloaded;
|
||||
return;
|
||||
}
|
||||
|
||||
private void PinBox_Unloaded(object sender, RoutedEventArgs e)
|
||||
if (_panel.Children.Count == 0)
|
||||
{
|
||||
RemoveHandler(System.Windows.Controls.PasswordBox.PasswordChangedEvent, _passwordBoxsPasswordChangedEventHandler);
|
||||
RemoveHandler(GotFocusEvent, _passwordBoxsGotFocusEventHandler);
|
||||
|
||||
Loaded -= PinBox_Loaded;
|
||||
Unloaded -= PinBox_Unloaded;
|
||||
return;
|
||||
}
|
||||
|
||||
private void PinBox_Loaded(object sender, RoutedEventArgs e)
|
||||
if (_panel.Children.OfType<System.Windows.Controls.PasswordBox>().Any(box => box.IsFocused))
|
||||
{
|
||||
_passwordBoxsPasswordChangedEventHandler = PasswordBoxsPasswordChanged;
|
||||
AddHandler(System.Windows.Controls.PasswordBox.PasswordChangedEvent, _passwordBoxsPasswordChangedEventHandler);
|
||||
|
||||
_passwordBoxsGotFocusEventHandler = PasswordBoxsGotFocus;
|
||||
AddHandler(GotFocusEvent, _passwordBoxsGotFocusEventHandler);
|
||||
|
||||
FocusPasswordBox();
|
||||
return;
|
||||
}
|
||||
|
||||
private void FocusPasswordBox()
|
||||
FocusManager.SetFocusedElement(this, _panel.Children[0]);
|
||||
}
|
||||
|
||||
private void PasswordBoxsPasswordChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_isInternalAction) return;
|
||||
|
||||
if (e.OriginalSource is System.Windows.Controls.PasswordBox passwordBox)
|
||||
{
|
||||
if (!IsFocused)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_panel.Children.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_panel.Children.OfType<System.Windows.Controls.PasswordBox>().Any(box => box.IsFocused))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FocusManager.SetFocusedElement(this, _panel.Children[0]);
|
||||
}
|
||||
|
||||
private void PasswordBoxsPasswordChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_isInternalAction) return;
|
||||
|
||||
if (e.OriginalSource is System.Windows.Controls.PasswordBox passwordBox)
|
||||
{
|
||||
if (passwordBox.Password.Length > 0)
|
||||
{
|
||||
if (++_inputIndex >= Length)
|
||||
{
|
||||
_inputIndex = Length - 1;
|
||||
|
||||
if (_panel.Children.OfType<System.Windows.Controls.PasswordBox>()
|
||||
.All(item => item.Password.Any()))
|
||||
{
|
||||
FocusManager.SetFocusedElement(this, null);
|
||||
Keyboard.ClearFocus();
|
||||
RaiseEvent(new RoutedEventArgs(CompletedEvent, this));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (--_inputIndex < 0)
|
||||
{
|
||||
_inputIndex = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_changed = true;
|
||||
FocusManager.SetFocusedElement(this, _panel.Children[_inputIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
private void PasswordBoxsGotFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (e.OriginalSource is System.Windows.Controls.PasswordBox passwordBox)
|
||||
{
|
||||
_inputIndex = _panel.Children.IndexOf(passwordBox);
|
||||
passwordBox.SelectAll();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPreviewKeyDown(KeyEventArgs e)
|
||||
{
|
||||
base.OnPreviewKeyUp(e);
|
||||
|
||||
if (e.Key == Key.Left)
|
||||
{
|
||||
if (--_inputIndex < 0)
|
||||
{
|
||||
_inputIndex = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
var passwordBox = _panel.Children[_inputIndex] as System.Windows.Controls.PasswordBox;
|
||||
passwordBox?.SelectAll();
|
||||
|
||||
FocusManager.SetFocusedElement(this, passwordBox);
|
||||
}
|
||||
else if (e.Key == Key.Right)
|
||||
if (passwordBox.Password.Length > 0)
|
||||
{
|
||||
if (++_inputIndex >= Length)
|
||||
{
|
||||
_inputIndex = Length - 1;
|
||||
|
||||
if (_panel.Children.OfType<System.Windows.Controls.PasswordBox>()
|
||||
.All(item => item.Password.Any()))
|
||||
{
|
||||
FocusManager.SetFocusedElement(this, null);
|
||||
Keyboard.ClearFocus();
|
||||
RaiseEvent(new RoutedEventArgs(CompletedEvent, this));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var passwordBox = _panel.Children[_inputIndex] as System.Windows.Controls.PasswordBox;
|
||||
passwordBox?.SelectAll();
|
||||
|
||||
FocusManager.SetFocusedElement(this, passwordBox);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPreviewKeyUp(KeyEventArgs e)
|
||||
{
|
||||
base.OnPreviewKeyUp(e);
|
||||
|
||||
if (_changed)
|
||||
else
|
||||
{
|
||||
_changed = false;
|
||||
return;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
_inputIndex = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
FocusManager.SetFocusedElement(this, _panel.Children[_inputIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
public string Password
|
||||
_changed = true;
|
||||
FocusManager.SetFocusedElement(this, _panel.Children[_inputIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
private void PasswordBoxsGotFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (e.OriginalSource is System.Windows.Controls.PasswordBox passwordBox)
|
||||
{
|
||||
get
|
||||
_inputIndex = _panel.Children.IndexOf(passwordBox);
|
||||
passwordBox.SelectAll();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPreviewKeyDown(KeyEventArgs e)
|
||||
{
|
||||
base.OnPreviewKeyUp(e);
|
||||
|
||||
if (e.Key == Key.Left)
|
||||
{
|
||||
if (--_inputIndex < 0)
|
||||
{
|
||||
return string.Join("", _panel.Children.OfType<System.Windows.Controls.PasswordBox>().Select(item => item.Password));
|
||||
_inputIndex = 0;
|
||||
return;
|
||||
}
|
||||
set
|
||||
|
||||
var passwordBox = _panel.Children[_inputIndex] as System.Windows.Controls.PasswordBox;
|
||||
passwordBox?.SelectAll();
|
||||
|
||||
FocusManager.SetFocusedElement(this, passwordBox);
|
||||
}
|
||||
else if (e.Key == Key.Right)
|
||||
{
|
||||
if (++_inputIndex >= Length)
|
||||
{
|
||||
if (_panel == null)
|
||||
{
|
||||
_passwordList = new List<SecureString>();
|
||||
|
||||
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());
|
||||
}
|
||||
_inputIndex = Length - 1;
|
||||
return;
|
||||
}
|
||||
|
||||
var passwordBox = _panel.Children[_inputIndex] as System.Windows.Controls.PasswordBox;
|
||||
passwordBox?.SelectAll();
|
||||
|
||||
FocusManager.SetFocusedElement(this, passwordBox);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPreviewKeyUp(KeyEventArgs e)
|
||||
{
|
||||
base.OnPreviewKeyUp(e);
|
||||
|
||||
if (_changed)
|
||||
{
|
||||
_changed = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 掩码字符
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PasswordCharProperty =
|
||||
System.Windows.Controls.PasswordBox.PasswordCharProperty.AddOwner(typeof(PinBox),
|
||||
new FrameworkPropertyMetadata('●'));
|
||||
|
||||
public char PasswordChar
|
||||
if (e.Key == Key.Delete || e.Key == Key.Back)
|
||||
{
|
||||
get => (char) GetValue(PasswordCharProperty);
|
||||
set => SetValue(PasswordCharProperty, value);
|
||||
if (_panel.Children[_inputIndex] is System.Windows.Controls.PasswordBox passwordBox)
|
||||
{
|
||||
_isInternalAction = true;
|
||||
passwordBox.Clear();
|
||||
_isInternalAction = false;
|
||||
}
|
||||
|
||||
if (--_inputIndex < 0)
|
||||
{
|
||||
_inputIndex = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
FocusManager.SetFocusedElement(this, _panel.Children[_inputIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty LengthProperty = DependencyProperty.Register(
|
||||
"Length", typeof(int), typeof(PinBox), new PropertyMetadata(MinLength, OnLengthChanged, CoerceLength), ValidateHelper.IsInRangeOfPosInt);
|
||||
|
||||
private static void OnLengthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
public string Password
|
||||
{
|
||||
get
|
||||
{
|
||||
var ctl = (PinBox) d;
|
||||
ctl.UpdateItems();
|
||||
return string.Join("", _panel.Children.OfType<System.Windows.Controls.PasswordBox>().Select(item => item.Password));
|
||||
}
|
||||
|
||||
private static object CoerceLength(DependencyObject d, object basevalue) => (int) basevalue < 4 ? MinLength : basevalue;
|
||||
|
||||
public int Length
|
||||
set
|
||||
{
|
||||
get => (int) GetValue(LengthProperty);
|
||||
set => SetValue(LengthProperty, value);
|
||||
}
|
||||
if (_panel == null)
|
||||
{
|
||||
_passwordList = new List<SecureString>();
|
||||
|
||||
public static readonly DependencyProperty ItemMarginProperty = DependencyProperty.Register(
|
||||
"ItemMargin", typeof(Thickness), typeof(PinBox), new PropertyMetadata(default(Thickness)));
|
||||
value ??= string.Empty;
|
||||
|
||||
public Thickness ItemMargin
|
||||
{
|
||||
get => (Thickness) GetValue(ItemMarginProperty);
|
||||
set => SetValue(ItemMarginProperty, value);
|
||||
}
|
||||
foreach (var item in value)
|
||||
{
|
||||
var secureString = new SecureString();
|
||||
secureString.AppendChar(item);
|
||||
_passwordList.Add(secureString);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ItemWidthProperty = DependencyProperty.Register(
|
||||
"ItemWidth", typeof(double), typeof(PinBox), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
return;
|
||||
}
|
||||
|
||||
public double ItemWidth
|
||||
{
|
||||
get => (double) GetValue(ItemWidthProperty);
|
||||
set => SetValue(ItemWidthProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ItemHeightProperty = DependencyProperty.Register(
|
||||
"ItemHeight", typeof(double), typeof(PinBox), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
|
||||
public double ItemHeight
|
||||
{
|
||||
get => (double) GetValue(ItemHeightProperty);
|
||||
set => SetValue(ItemHeightProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectionBrushProperty =
|
||||
TextBoxBase.SelectionBrushProperty.AddOwner(typeof(PinBox));
|
||||
|
||||
public Brush SelectionBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionBrushProperty);
|
||||
set => SetValue(SelectionBrushProperty, value);
|
||||
}
|
||||
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
|
||||
public static readonly DependencyProperty SelectionTextBrushProperty =
|
||||
TextBoxBase.SelectionTextBrushProperty.AddOwner(typeof(PinBox));
|
||||
|
||||
public Brush SelectionTextBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionTextBrushProperty);
|
||||
set => SetValue(SelectionTextBrushProperty, value);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public static readonly DependencyProperty SelectionOpacityProperty =
|
||||
TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(PinBox));
|
||||
|
||||
public double SelectionOpacity
|
||||
{
|
||||
get => (double) GetValue(SelectionOpacityProperty);
|
||||
set => SetValue(SelectionOpacityProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CaretBrushProperty =
|
||||
TextBoxBase.CaretBrushProperty.AddOwner(typeof(PinBox));
|
||||
|
||||
public Brush CaretBrush
|
||||
{
|
||||
get => (Brush) GetValue(CaretBrushProperty);
|
||||
set => SetValue(CaretBrushProperty, value);
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent CompletedEvent =
|
||||
EventManager.RegisterRoutedEvent("Completed", RoutingStrategy.Bubble,
|
||||
typeof(RoutedEventHandler), typeof(PinBox));
|
||||
|
||||
public event RoutedEventHandler Completed
|
||||
{
|
||||
add => AddHandler(CompletedEvent, value);
|
||||
remove => RemoveHandler(CompletedEvent, value);
|
||||
}
|
||||
|
||||
private void UpdateItems()
|
||||
{
|
||||
if (_panel == null) return;
|
||||
|
||||
_panel.Children.Clear();
|
||||
var length = Length;
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
if (string.IsNullOrEmpty(value) || value.Length != length || value.Length != _panel.Children.Count)
|
||||
{
|
||||
_panel.Children.Add(CreatePasswordBox());
|
||||
_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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private System.Windows.Controls.PasswordBox CreatePasswordBox()
|
||||
{
|
||||
var passwordBox = new System.Windows.Controls.PasswordBox
|
||||
{
|
||||
MaxLength = 1,
|
||||
HorizontalContentAlignment = HorizontalAlignment.Center,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
Margin = ItemMargin,
|
||||
Width = ItemWidth,
|
||||
Height = ItemHeight,
|
||||
Padding = default,
|
||||
PasswordChar = PasswordChar,
|
||||
Foreground = Foreground
|
||||
};
|
||||
/// <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(
|
||||
"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;
|
||||
|
||||
public int Length
|
||||
{
|
||||
get => (int) GetValue(LengthProperty);
|
||||
set => SetValue(LengthProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ItemMarginProperty = DependencyProperty.Register(
|
||||
"ItemMargin", typeof(Thickness), typeof(PinBox), new PropertyMetadata(default(Thickness)));
|
||||
|
||||
public Thickness ItemMargin
|
||||
{
|
||||
get => (Thickness) GetValue(ItemMarginProperty);
|
||||
set => SetValue(ItemMarginProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ItemWidthProperty = DependencyProperty.Register(
|
||||
"ItemWidth", typeof(double), typeof(PinBox), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
|
||||
public double ItemWidth
|
||||
{
|
||||
get => (double) GetValue(ItemWidthProperty);
|
||||
set => SetValue(ItemWidthProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ItemHeightProperty = DependencyProperty.Register(
|
||||
"ItemHeight", typeof(double), typeof(PinBox), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
|
||||
public double ItemHeight
|
||||
{
|
||||
get => (double) GetValue(ItemHeightProperty);
|
||||
set => SetValue(ItemHeightProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectionBrushProperty =
|
||||
TextBoxBase.SelectionBrushProperty.AddOwner(typeof(PinBox));
|
||||
|
||||
public Brush SelectionBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionBrushProperty);
|
||||
set => SetValue(SelectionBrushProperty, value);
|
||||
}
|
||||
|
||||
passwordBox.SetBinding(SelectionBrushProperty, new Binding(SelectionBrushProperty.Name) { Source = this });
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
passwordBox.SetBinding(SelectionTextBrushProperty, new Binding(SelectionTextBrushProperty.Name) { Source = this });
|
||||
|
||||
public static readonly DependencyProperty SelectionTextBrushProperty =
|
||||
TextBoxBase.SelectionTextBrushProperty.AddOwner(typeof(PinBox));
|
||||
|
||||
public Brush SelectionTextBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionTextBrushProperty);
|
||||
set => SetValue(SelectionTextBrushProperty, value);
|
||||
}
|
||||
|
||||
#endif
|
||||
passwordBox.SetBinding(SelectionOpacityProperty, new Binding(SelectionOpacityProperty.Name) { Source = this });
|
||||
passwordBox.SetBinding(CaretBrushProperty, new Binding(CaretBrushProperty.Name) { Source = this });
|
||||
|
||||
return passwordBox;
|
||||
}
|
||||
public static readonly DependencyProperty SelectionOpacityProperty =
|
||||
TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(PinBox));
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
public double SelectionOpacity
|
||||
{
|
||||
get => (double) GetValue(SelectionOpacityProperty);
|
||||
set => SetValue(SelectionOpacityProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CaretBrushProperty =
|
||||
TextBoxBase.CaretBrushProperty.AddOwner(typeof(PinBox));
|
||||
|
||||
public Brush CaretBrush
|
||||
{
|
||||
get => (Brush) GetValue(CaretBrushProperty);
|
||||
set => SetValue(CaretBrushProperty, value);
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent CompletedEvent =
|
||||
EventManager.RegisterRoutedEvent("Completed", RoutingStrategy.Bubble,
|
||||
typeof(RoutedEventHandler), typeof(PinBox));
|
||||
|
||||
public event RoutedEventHandler Completed
|
||||
{
|
||||
add => AddHandler(CompletedEvent, value);
|
||||
remove => RemoveHandler(CompletedEvent, value);
|
||||
}
|
||||
|
||||
private void UpdateItems()
|
||||
{
|
||||
if (_panel == null) return;
|
||||
|
||||
_panel.Children.Clear();
|
||||
var length = Length;
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
_panel.Children.Add(CreatePasswordBox());
|
||||
}
|
||||
}
|
||||
|
||||
_panel = GetTemplateChild(ElementPanel) as Panel;
|
||||
if (_panel != null)
|
||||
private System.Windows.Controls.PasswordBox CreatePasswordBox()
|
||||
{
|
||||
var passwordBox = new System.Windows.Controls.PasswordBox
|
||||
{
|
||||
MaxLength = 1,
|
||||
HorizontalContentAlignment = HorizontalAlignment.Center,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
Margin = ItemMargin,
|
||||
Width = ItemWidth,
|
||||
Height = ItemHeight,
|
||||
Padding = default,
|
||||
PasswordChar = PasswordChar,
|
||||
Foreground = Foreground
|
||||
};
|
||||
|
||||
passwordBox.SetBinding(SelectionBrushProperty, new Binding(SelectionBrushProperty.Name) { Source = this });
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
passwordBox.SetBinding(SelectionTextBrushProperty, new Binding(SelectionTextBrushProperty.Name) { Source = this });
|
||||
#endif
|
||||
passwordBox.SetBinding(SelectionOpacityProperty, new Binding(SelectionOpacityProperty.Name) { Source = this });
|
||||
passwordBox.SetBinding(CaretBrushProperty, new Binding(CaretBrushProperty.Name) { Source = this });
|
||||
|
||||
return passwordBox;
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_panel = GetTemplateChild(ElementPanel) as Panel;
|
||||
if (_panel != null)
|
||||
{
|
||||
UpdateItems();
|
||||
|
||||
var length = Length;
|
||||
if (_passwordList != null && _passwordList.Count == length && _panel.Children.Count == length)
|
||||
{
|
||||
UpdateItems();
|
||||
|
||||
var length = Length;
|
||||
if (_passwordList != null && _passwordList.Count == length && _panel.Children.Count == length)
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
for (var i = 0; i < length; i++)
|
||||
var password = _passwordList[i];
|
||||
if (password.Length > 0)
|
||||
{
|
||||
var password = _passwordList[i];
|
||||
if (password.Length > 0)
|
||||
var valuePtr = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
var valuePtr = IntPtr.Zero;
|
||||
try
|
||||
valuePtr = Marshal.SecureStringToGlobalAllocUnicode(password);
|
||||
if (_panel.Children[i] is System.Windows.Controls.PasswordBox passwordBox)
|
||||
{
|
||||
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();
|
||||
passwordBox.Password = Marshal.PtrToStringUni(valuePtr) ?? throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
|
||||
password.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
_passwordList.Clear();
|
||||
}
|
||||
|
||||
_passwordList.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,128 +5,126 @@ using System.Windows.Input;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Interactivity;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class SearchBar : TextBox, ICommandSource
|
||||
{
|
||||
public class SearchBar : TextBox, ICommandSource
|
||||
public SearchBar()
|
||||
{
|
||||
public SearchBar()
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Search, (s, e) => OnSearchStarted()));
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent SearchStartedEvent =
|
||||
EventManager.RegisterRoutedEvent("SearchStarted", RoutingStrategy.Bubble,
|
||||
typeof(EventHandler<FunctionEventArgs<string>>), typeof(SearchBar));
|
||||
|
||||
public event EventHandler<FunctionEventArgs<string>> SearchStarted
|
||||
{
|
||||
add => AddHandler(SearchStartedEvent, value);
|
||||
remove => RemoveHandler(SearchStartedEvent, value);
|
||||
}
|
||||
|
||||
protected override void OnKeyDown(KeyEventArgs e)
|
||||
{
|
||||
base.OnKeyDown(e);
|
||||
|
||||
if (e.Key == Key.Enter)
|
||||
{
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Search, (s, e) => OnSearchStarted()));
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent SearchStartedEvent =
|
||||
EventManager.RegisterRoutedEvent("SearchStarted", RoutingStrategy.Bubble,
|
||||
typeof(EventHandler<FunctionEventArgs<string>>), typeof(SearchBar));
|
||||
|
||||
public event EventHandler<FunctionEventArgs<string>> SearchStarted
|
||||
{
|
||||
add => AddHandler(SearchStartedEvent, value);
|
||||
remove => RemoveHandler(SearchStartedEvent, value);
|
||||
}
|
||||
|
||||
protected override void OnKeyDown(KeyEventArgs e)
|
||||
{
|
||||
base.OnKeyDown(e);
|
||||
|
||||
if (e.Key == Key.Enter)
|
||||
{
|
||||
OnSearchStarted();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnTextChanged(TextChangedEventArgs e)
|
||||
{
|
||||
base.OnTextChanged(e);
|
||||
|
||||
if (IsRealTime)
|
||||
{
|
||||
OnSearchStarted();
|
||||
}
|
||||
VerifyData();
|
||||
}
|
||||
|
||||
private void OnSearchStarted()
|
||||
{
|
||||
RaiseEvent(new FunctionEventArgs<string>(SearchStartedEvent, this)
|
||||
{
|
||||
Info = Text
|
||||
});
|
||||
|
||||
switch (Command)
|
||||
{
|
||||
case null:
|
||||
return;
|
||||
case RoutedCommand command:
|
||||
command.Execute(CommandParameter, CommandTarget);
|
||||
break;
|
||||
default:
|
||||
Command.Execute(CommandParameter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否实时搜索
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsRealTimeProperty = DependencyProperty.Register(
|
||||
"IsRealTime", typeof(bool), typeof(SearchBar), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
/// <summary>
|
||||
/// 是否实时搜索
|
||||
/// </summary>
|
||||
public bool IsRealTime
|
||||
{
|
||||
get => (bool) GetValue(IsRealTimeProperty);
|
||||
set => SetValue(IsRealTimeProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
|
||||
"Command", typeof(ICommand), typeof(SearchBar), new PropertyMetadata(default(ICommand), OnCommandChanged));
|
||||
|
||||
private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (SearchBar) d;
|
||||
if (e.OldValue is ICommand oldCommand)
|
||||
{
|
||||
oldCommand.CanExecuteChanged -= ctl.CanExecuteChanged;
|
||||
}
|
||||
if (e.NewValue is ICommand newCommand)
|
||||
{
|
||||
newCommand.CanExecuteChanged += ctl.CanExecuteChanged;
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand Command
|
||||
{
|
||||
get => (ICommand) GetValue(CommandProperty);
|
||||
set => SetValue(CommandProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(
|
||||
"CommandParameter", typeof(object), typeof(SearchBar), new PropertyMetadata(default(object)));
|
||||
|
||||
public object CommandParameter
|
||||
{
|
||||
get => GetValue(CommandParameterProperty);
|
||||
set => SetValue(CommandParameterProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CommandTargetProperty = DependencyProperty.Register(
|
||||
"CommandTarget", typeof(IInputElement), typeof(SearchBar), new PropertyMetadata(default(IInputElement)));
|
||||
|
||||
public IInputElement CommandTarget
|
||||
{
|
||||
get => (IInputElement) GetValue(CommandTargetProperty);
|
||||
set => SetValue(CommandTargetProperty, value);
|
||||
}
|
||||
|
||||
private void CanExecuteChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (Command == null) return;
|
||||
|
||||
IsEnabled = Command is RoutedCommand command
|
||||
? command.CanExecute(CommandParameter, CommandTarget)
|
||||
: Command.CanExecute(CommandParameter);
|
||||
OnSearchStarted();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnTextChanged(TextChangedEventArgs e)
|
||||
{
|
||||
base.OnTextChanged(e);
|
||||
|
||||
if (IsRealTime)
|
||||
{
|
||||
OnSearchStarted();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSearchStarted()
|
||||
{
|
||||
RaiseEvent(new FunctionEventArgs<string>(SearchStartedEvent, this)
|
||||
{
|
||||
Info = Text
|
||||
});
|
||||
|
||||
switch (Command)
|
||||
{
|
||||
case null:
|
||||
return;
|
||||
case RoutedCommand command:
|
||||
command.Execute(CommandParameter, CommandTarget);
|
||||
break;
|
||||
default:
|
||||
Command.Execute(CommandParameter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否实时搜索
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsRealTimeProperty = DependencyProperty.Register(
|
||||
"IsRealTime", typeof(bool), typeof(SearchBar), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
/// <summary>
|
||||
/// 是否实时搜索
|
||||
/// </summary>
|
||||
public bool IsRealTime
|
||||
{
|
||||
get => (bool) GetValue(IsRealTimeProperty);
|
||||
set => SetValue(IsRealTimeProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
|
||||
"Command", typeof(ICommand), typeof(SearchBar), new PropertyMetadata(default(ICommand), OnCommandChanged));
|
||||
|
||||
private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (SearchBar) d;
|
||||
if (e.OldValue is ICommand oldCommand)
|
||||
{
|
||||
oldCommand.CanExecuteChanged -= ctl.CanExecuteChanged;
|
||||
}
|
||||
if (e.NewValue is ICommand newCommand)
|
||||
{
|
||||
newCommand.CanExecuteChanged += ctl.CanExecuteChanged;
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand Command
|
||||
{
|
||||
get => (ICommand) GetValue(CommandProperty);
|
||||
set => SetValue(CommandProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(
|
||||
"CommandParameter", typeof(object), typeof(SearchBar), new PropertyMetadata(default(object)));
|
||||
|
||||
public object CommandParameter
|
||||
{
|
||||
get => GetValue(CommandParameterProperty);
|
||||
set => SetValue(CommandParameterProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CommandTargetProperty = DependencyProperty.Register(
|
||||
"CommandTarget", typeof(IInputElement), typeof(SearchBar), new PropertyMetadata(default(IInputElement)));
|
||||
|
||||
public IInputElement CommandTarget
|
||||
{
|
||||
get => (IInputElement) GetValue(CommandTargetProperty);
|
||||
set => SetValue(CommandTargetProperty, value);
|
||||
}
|
||||
|
||||
private void CanExecuteChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (Command == null) return;
|
||||
|
||||
IsEnabled = Command is RoutedCommand command
|
||||
? command.CanExecute(CommandParameter, CommandTarget)
|
||||
: Command.CanExecute(CommandParameter);
|
||||
}
|
||||
}
|
||||
@@ -1,138 +1,15 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using HandyControl.Data;
|
||||
using System.Windows.Input;
|
||||
using HandyControl.Interactivity;
|
||||
using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class TextBox : System.Windows.Controls.TextBox
|
||||
{
|
||||
public class TextBox : System.Windows.Controls.TextBox, IDataInput
|
||||
public TextBox()
|
||||
{
|
||||
public TextBox()
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
|
||||
{
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
|
||||
{
|
||||
SetCurrentValue(TextProperty, "");
|
||||
}));
|
||||
}
|
||||
|
||||
protected override void OnTextChanged(TextChangedEventArgs e)
|
||||
{
|
||||
base.OnTextChanged(e);
|
||||
VerifyData();
|
||||
}
|
||||
|
||||
public Func<string, OperationResult<bool>> VerifyFunc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据是否错误
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register(
|
||||
"IsError", typeof(bool), typeof(TextBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool IsError
|
||||
{
|
||||
get => (bool) GetValue(IsErrorProperty);
|
||||
set => SetValue(IsErrorProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 错误提示
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ErrorStrProperty = DependencyProperty.Register(
|
||||
"ErrorStr", typeof(string), typeof(TextBox), new PropertyMetadata(default(string)));
|
||||
|
||||
public string ErrorStr
|
||||
{
|
||||
get => (string) GetValue(ErrorStrProperty);
|
||||
set => SetValue(ErrorStrProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TextTypeProperty = DependencyProperty.Register(
|
||||
"TextType", typeof(TextType), typeof(TextBox), new PropertyMetadata(default(TextType)));
|
||||
|
||||
public TextType TextType
|
||||
{
|
||||
get => (TextType) GetValue(TextTypeProperty);
|
||||
set => SetValue(TextTypeProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示清除按钮
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ShowClearButtonProperty = DependencyProperty.Register(
|
||||
"ShowClearButton", typeof(bool), typeof(TextBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool ShowClearButton
|
||||
{
|
||||
get => (bool) GetValue(ShowClearButtonProperty);
|
||||
set => SetValue(ShowClearButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public virtual bool VerifyData()
|
||||
{
|
||||
OperationResult<bool> result;
|
||||
|
||||
if (VerifyFunc != null)
|
||||
{
|
||||
result = VerifyFunc.Invoke(Text);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
if (TextType != TextType.Common)
|
||||
{
|
||||
var regexPattern = InfoElement.GetRegexPattern(this);
|
||||
result = string.IsNullOrEmpty(regexPattern)
|
||||
? Text.IsKindOf(TextType)
|
||||
? OperationResult.Success()
|
||||
: OperationResult.Failed(Properties.Langs.Lang.FormatError)
|
||||
: Text.IsKindOf(regexPattern)
|
||||
? OperationResult.Success()
|
||||
: OperationResult.Failed(Properties.Langs.Lang.FormatError);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
}
|
||||
else if (InfoElement.GetNecessary(this))
|
||||
{
|
||||
result = OperationResult.Failed(Properties.Langs.Lang.IsNecessary);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
}
|
||||
|
||||
var isError = !result.Data;
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.TrueBox);
|
||||
SetCurrentValue(ErrorStrProperty, result.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.FalseBox);
|
||||
SetCurrentValue(ErrorStrProperty, default(string));
|
||||
}
|
||||
}
|
||||
|
||||
return !isError;
|
||||
}
|
||||
SetCurrentValue(TextProperty, string.Empty);
|
||||
}));
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,35 +1,34 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class WatermarkTextBox : TextBox
|
||||
{
|
||||
public class WatermarkTextBox : TextBox
|
||||
#region Public Properties
|
||||
|
||||
#region Watermark
|
||||
|
||||
public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register(
|
||||
"Watermark", typeof(object), typeof(WatermarkTextBox), new PropertyMetadata(default(object)));
|
||||
|
||||
public object Watermark
|
||||
{
|
||||
#region Public Properties
|
||||
get => GetValue(WatermarkProperty);
|
||||
set => SetValue(WatermarkProperty, value);
|
||||
}
|
||||
|
||||
#region Watermark
|
||||
#endregion Watermark
|
||||
|
||||
public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register(
|
||||
"Watermark", typeof(object), typeof(WatermarkTextBox), new PropertyMetadata(default(object)));
|
||||
#endregion Public Properties
|
||||
|
||||
public object Watermark
|
||||
protected override void OnGotFocus(RoutedEventArgs e)
|
||||
{
|
||||
base.OnGotFocus(e);
|
||||
if (IsEnabled)
|
||||
{
|
||||
get => GetValue(WatermarkProperty);
|
||||
set => SetValue(WatermarkProperty, value);
|
||||
}
|
||||
|
||||
#endregion Watermark
|
||||
|
||||
#endregion Public Properties
|
||||
|
||||
protected override void OnGotFocus(RoutedEventArgs e)
|
||||
{
|
||||
base.OnGotFocus(e);
|
||||
if (IsEnabled)
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
Select(0, Text.Length);
|
||||
}
|
||||
Select(0, Text.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user