Merge branch 'master' into patch-2

This commit is contained in:
NaBian authored and GitHub committed 2022-03-27 19:59:10 +08:00
commit f35a2647da
986 files changed
+63640 -61515

No files matched your search

@@ -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);
}
}
}
@@ -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);
}
}
}