基于WPF實(shí)現(xiàn)數(shù)字框控件
WPF 實(shí)現(xiàn)數(shù)字框控件
框架使用.NET4 至 .NET6
;
Visual Studio 2022
;
實(shí)現(xiàn)代碼
1)新增 NumericBox.cs
代碼如下:
OnPreviewKeyDown
方法:
- 處理
Enter
鍵:調(diào)用DealInputText
方法處理輸入文本,選擇所有文本,并標(biāo)記事件為已處理。 - 處理向上箭頭鍵:調(diào)用
ContinueChangeValue
方法增加NumericBox
值,并標(biāo)記事件為已處理。 - 處理向下箭頭鍵:調(diào)用
ContinueChangeValue
方法減少NumericBox
值,并標(biāo)記事件為已處理。
OnPreviewKeyUp
方法:
處理釋放的向上箭頭鍵或向下箭頭鍵:調(diào)用 ResetInternal
方法重置 NumericBox
內(nèi)部狀態(tài)。
嘗試將輸入的文本轉(zhuǎn)換為 double
類型的數(shù)值。
如果轉(zhuǎn)換成功:
檢查轉(zhuǎn)換后的值與當(dāng)前值是否非常接近,如果是,則不做任何操作。
否則,根據(jù)轉(zhuǎn)換后的值和最大值、最小值進(jìn)行比較:
如果大于最大值,則將值設(shè)置為最大值。
如果小于最小值,則將值設(shè)置為最小值。
否則,將值設(shè)置為轉(zhuǎn)換后的值。
如果轉(zhuǎn)換失敗,則將當(dāng)前值設(shè)置回文本框。
Precision
可輸入多少小數(shù)位。
using?System; using?System.Collections.Generic; using?System.ComponentModel; using?System.Diagnostics; using?System.Linq; using?System.Runtime.InteropServices; using?System.Text; using?System.Windows.Controls.Primitives; using?System.Windows.Input; using?System.Windows; using?System.Xml.Linq; using?WPFDevelopers.Utilities; using?System.Windows.Controls; using?WPFDevelopers.Datas; namespace?WPFDevelopers.Controls { ????[DefaultEvent("ValueChanged"),?DefaultProperty("Value")] ????[TemplatePart(Name?=?TextBoxTemplateName,?Type?=?typeof(TextBox))] ????[TemplatePart(Name?=?NumericUpTemplateName,?Type?=?typeof(RepeatButton))] ????[TemplatePart(Name?=?NumericDownTemplateName,?Type?=?typeof(RepeatButton))] ????public?class?NumericBox?:?Control ????{ ????????private?static?readonly?Type?_typeofSelf?=?typeof(NumericBox); ????????private?const?double?DefaultInterval?=?1d; ????????private?const?int?DefaultDelay?=?500; ????????private?const?string?TextBoxTemplateName?=?"PART_TextBox"; ????????private?const?string?NumericUpTemplateName?=?"PART_NumericUp"; ????????private?const?string?NumericDownTemplateName?=?"PART_NumericDown"; ????????private?static?RoutedCommand?_increaseCommand?=?null; ????????private?static?RoutedCommand?_decreaseCommand?=?null; ????????private?TextBox?_valueTextBox; ????????private?RepeatButton?_repeatUp; ????????private?RepeatButton?_repeatDown; ????????private?double?_internalLargeChange?=?DefaultInterval; ????????private?double?_intervalValueSinceReset?=?0; ????????private?double??_lastOldValue?=?null; ????????private?bool?_isManual; ????????private?bool?_isBusy; ????????static?NumericBox() ????????{ ????????????InitializeCommands(); ????????????DefaultStyleKeyProperty.OverrideMetadata(_typeofSelf,?new?FrameworkPropertyMetadata(_typeofSelf)); ????????} ????????#region?Command ????????private?static?void?InitializeCommands() ????????{ ????????????_increaseCommand?=?new?RoutedCommand("Increase",?_typeofSelf); ????????????_decreaseCommand?=?new?RoutedCommand("Decrease",?_typeofSelf); ????????????CommandManager.RegisterClassCommandBinding(_typeofSelf,?new?CommandBinding(_increaseCommand,?OnIncreaseCommand,?OnCanIncreaseCommand)); ????????????CommandManager.RegisterClassCommandBinding(_typeofSelf,?new?CommandBinding(_decreaseCommand,?OnDecreaseCommand,?OnCanDecreaseCommand)); ????????} ????????public?static?RoutedCommand?IncreaseCommand ????????{ ????????????get?{?return?_increaseCommand;?} ????????} ????????public?static?RoutedCommand?DecreaseCommand ????????{ ????????????get?{?return?_decreaseCommand;?} ????????} ????????private?static?void?OnIncreaseCommand(object?sender,?RoutedEventArgs?e) ????????{ ????????????var?numericBox?=?sender?as?NumericBox; ????????????numericBox.ContinueChangeValue(true); ????????} ????????private?static?void?OnCanIncreaseCommand(object?sender,?CanExecuteRoutedEventArgs?e) ????????{ ????????????var?numericBox?=?sender?as?NumericBox; ????????????e.CanExecute?=?(!numericBox.IsReadOnly?&&?numericBox.IsEnabled?&&?DoubleUtil.LessThan(numericBox.Value,?numericBox.Maximum)); ????????} ????????private?static?void?OnDecreaseCommand(object?sender,?RoutedEventArgs?e) ????????{ ????????????var?numericBox?=?sender?as?NumericBox; ????????????numericBox.ContinueChangeValue(false); ????????} ????????private?static?void?OnCanDecreaseCommand(object?sender,?CanExecuteRoutedEventArgs?e) ????????{ ????????????var?numericBox?=?sender?as?NumericBox; ????????????e.CanExecute?=?(!numericBox.IsReadOnly?&&?numericBox.IsEnabled?&&?DoubleUtil.GreaterThan(numericBox.Value,?numericBox.Minimum)); ????????} ????????#endregion ????????#region?RouteEvent ????????public?static?readonly?RoutedEvent?ValueChangedEvent?=?EventManager.RegisterRoutedEvent("ValueChanged",?RoutingStrategy.Bubble,?typeof(RoutedPropertyChangedEventHandler<double>),?_typeofSelf); ????????public?event?RoutedPropertyChangedEventHandler<double>?ValueChanged ????????{ ????????????add?{?AddHandler(ValueChangedEvent,?value);?} ????????????remove?{?RemoveHandler(ValueChangedEvent,?value);?} ????????} ????????#endregion ????????#region?Properties ????????public?static?readonly?DependencyProperty?DisabledValueChangedWhileBusyProperty?=?DependencyProperty.Register("DisabledValueChangedWhileBusy",?typeof(bool),?_typeofSelf, ???????????new?PropertyMetadata(false)); ????????[Category("Common")] ????????[DefaultValue(true)] ????????public?bool?DisabledValueChangedWhileBusy ????????{ ????????????get?{?return?(bool)GetValue(DisabledValueChangedWhileBusyProperty);?} ????????????set?{?SetValue(DisabledValueChangedWhileBusyProperty,?value);?} ????????} ????????public?static?readonly?DependencyProperty?IntervalProperty?=?DependencyProperty.Register("Interval",?typeof(double),?_typeofSelf, ???????????new?FrameworkPropertyMetadata(DefaultInterval,?IntervalChanged,?CoerceInterval)); ????????[Category("Behavior")] ????????[DefaultValue(DefaultInterval)] ????????public?double?Interval ????????{ ????????????get?{?return?(double)GetValue(IntervalProperty);?} ????????????set?{?SetValue(IntervalProperty,?value);?} ????????} ????????private?static?object?CoerceInterval(DependencyObject?d,?object?value) ????????{ ????????????var?interval?=?(double)value; ????????????return?DoubleUtil.IsNaN(interval)???0?:?Math.Max(interval,?0); ????????} ????????private?static?void?IntervalChanged(DependencyObject?d,?DependencyPropertyChangedEventArgs?e) ????????{ ????????????var?numericBox?=?(NumericBox)d; ????????????numericBox.ResetInternal(); ????????} ????????public?static?readonly?DependencyProperty?SpeedupProperty?=?DependencyProperty.Register("Speedup",?typeof(bool),?_typeofSelf, ???????????new?PropertyMetadata(true)); ????????[Category("Common")] ????????[DefaultValue(true)] ????????public?bool?Speedup ????????{ ????????????get?{?return?(bool)GetValue(SpeedupProperty);?} ????????????set?{?SetValue(SpeedupProperty,?value);?} ????????} ????????public?static?readonly?DependencyProperty?DelayProperty?=?DependencyProperty.Register("Delay",?typeof(int),?_typeofSelf, ????????????new?PropertyMetadata(DefaultDelay,?null,?CoerceDelay)); ????????[DefaultValue(DefaultDelay)] ????????[Category("Behavior")] ????????public?int?Delay ????????{ ????????????get?{?return?(int)GetValue(DelayProperty);?} ????????????set?{?SetValue(DelayProperty,?value);?} ????????} ????????private?static?object?CoerceDelay(DependencyObject?d,?object?value) ????????{ ????????????var?delay?=?(int)value; ????????????return?Math.Max(delay,?0); ????????} ????????public?static?readonly?DependencyProperty?UpDownButtonsWidthProperty?=?DependencyProperty.Register("UpDownButtonsWidth",?typeof(double),?_typeofSelf, ???????????new?PropertyMetadata(20d)); ????????[Category("Appearance")] ????????[DefaultValue(20d)] ????????public?double?UpDownButtonsWidth ????????{ ????????????get?{?return?(double)GetValue(UpDownButtonsWidthProperty);?} ????????????set?{?SetValue(UpDownButtonsWidthProperty,?value);?} ????????} ????????public?static?readonly?DependencyProperty?TextAlignmentProperty?=?TextBox.TextAlignmentProperty.AddOwner(_typeofSelf); ????????[Category("Common")] ????????public?TextAlignment?TextAlignment ????????{ ????????????get?{?return?(TextAlignment)GetValue(TextAlignmentProperty);?} ????????????set?{?SetValue(TextAlignmentProperty,?value);?} ????????} ????????public?static?readonly?DependencyProperty?IsReadOnlyProperty?=?TextBoxBase.IsReadOnlyProperty.AddOwner(_typeofSelf, ????????????new?FrameworkPropertyMetadata(false,?FrameworkPropertyMetadataOptions.Inherits,?IsReadOnlyPropertyChangedCallback)); ????????[Category("Appearance")] ????????public?bool?IsReadOnly ????????{ ????????????get?{?return?(bool)GetValue(IsReadOnlyProperty);?} ????????????set?{?SetValue(IsReadOnlyProperty,?value);?} ????????} ????????private?static?void?IsReadOnlyPropertyChangedCallback(DependencyObject?d,?DependencyPropertyChangedEventArgs?e) ????????{ ????????????if?(e.OldValue?==?e.NewValue?||?e.NewValue?==?null) ????????????????return; ????????????((NumericBox)d).ToggleReadOnlyMode((bool)e.NewValue); ????????} ????????public?static?readonly?DependencyProperty?PrecisionProperty?=?DependencyProperty.Register("Precision",?typeof(int?),?_typeofSelf, ????????????new?PropertyMetadata(null,?OnPrecisionChanged,?CoercePrecision)); ????????[Category("Common")] ????????public?int??Precision ????????{ ????????????get?{?return?(int?)GetValue(PrecisionProperty);?} ????????????set?{?SetValue(PrecisionProperty,?value);?} ????????} ????????private?static?object?CoercePrecision(DependencyObject?d,?object?value) ????????{ ????????????var?precision?=?(int?)value; ????????????return?(precision.HasValue?&&?precision.Value?<?0)???0?:?precision; ????????} ????????private?static?void?OnPrecisionChanged(DependencyObject?d,?DependencyPropertyChangedEventArgs?e) ????????{ ????????????var?numericBox?=?(NumericBox)d; ????????????var?newPrecision?=?(int?)e.NewValue; ????????????var?roundValue?=?numericBox.CorrectPrecision(newPrecision,?numericBox.Value); ????????????if?(DoubleUtil.AreClose(numericBox.Value,?roundValue)) ????????????????numericBox.InternalSetText(roundValue); ????????????else ????????????????numericBox.Value?=?roundValue; ????????} ????????public?static?readonly?DependencyProperty?MinimumProperty?=?DependencyProperty.Register("Minimum",?typeof(double),?_typeofSelf, ????????????new?PropertyMetadata(double.MinValue,?OnMinimumChanged)); ????????[Category("Common")] ????????public?double?Minimum ????????{ ????????????get?{?return?(double)GetValue(MinimumProperty);?} ????????????set?{?SetValue(MinimumProperty,?value);?} ????????} ????????private?static?void?OnMinimumChanged(DependencyObject?d,?DependencyPropertyChangedEventArgs?e) ????????{ ????????????var?numericBox?=?(NumericBox)d; ????????????numericBox.CoerceValue(MaximumProperty,?numericBox.Maximum); ????????????numericBox.CoerceValue(ValueProperty,?numericBox.Value); ????????} ????????public?static?readonly?DependencyProperty?MaximumProperty?=?DependencyProperty.Register("Maximum",?typeof(double),?_typeofSelf, ????????????new?PropertyMetadata(double.MaxValue,?OnMaximumChanged,?CoerceMaximum)); ????????[Category("Common")] ????????public?double?Maximum ????????{ ????????????get?{?return?(double)GetValue(MaximumProperty);?} ????????????set?{?SetValue(MaximumProperty,?value);?} ????????} ????????private?static?object?CoerceMaximum(DependencyObject?d,?object?value) ????????{ ????????????var?minimum?=?((NumericBox)d).Minimum; ????????????var?val?=?(double)value; ????????????return?DoubleUtil.LessThan(val,?minimum)???minimum?:?val; ????????} ????????private?static?void?OnMaximumChanged(DependencyObject?d,?DependencyPropertyChangedEventArgs?e) ????????{ ????????????var?numericBox?=?(NumericBox)d; ????????????numericBox.CoerceValue(ValueProperty,?numericBox.Value); ????????} ????????public?static?readonly?DependencyProperty?ValueProperty?=?DependencyProperty.Register("Value",?typeof(double),?_typeofSelf, ????????????new?FrameworkPropertyMetadata(0d,?FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,?OnValueChanged,?CoerceValue)); ????????[Category("Common")] ????????public?double?Value ????????{ ????????????get?{?return?(double)GetValue(ValueProperty);?} ????????????set?{?SetValue(ValueProperty,?value);?} ????????} ????????private?static?object?CoerceValue(DependencyObject?d,?object?value) ????????{ ????????????var?numericBox?=?(NumericBox)d; ????????????var?val?=?(double)value; ????????????if?(DoubleUtil.LessThan(val,?numericBox.Minimum)) ????????????????return?numericBox.Minimum; ????????????if?(DoubleUtil.GreaterThan(val,?numericBox.Maximum)) ????????????????return?numericBox.Maximum; ????????????return?numericBox.CorrectPrecision(numericBox.Precision,?val); ????????} ????????private?static?void?OnValueChanged(DependencyObject?d,?DependencyPropertyChangedEventArgs?e) ????????{ ????????????var?numericBox?=?(NumericBox)d; ????????????numericBox.OnValueChanged((double)e.OldValue,?(double)e.NewValue); ????????} ????????#endregion ????????#region?Virtual ????????protected?virtual?void?OnValueChanged(double?oldValue,?double?newValue) ????????{ ????????????InternalSetText(newValue); ????????????InvalidateRequerySuggested(newValue); ????????????if?((!_isBusy?||?!DisabledValueChangedWhileBusy)?&&?!DoubleUtil.AreClose(oldValue,?newValue)) ????????????{ ????????????????RaiseEvent(new?TextBoxValueChangedEventArgs<double>(oldValue,?newValue,?_isManual,?_isBusy,?ValueChangedEvent)); ????????????} ????????????_isManual?=?false; ????????} ????????#endregion ????????#region?Override ????????public?override?void?OnApplyTemplate() ????????{ ????????????base.OnApplyTemplate(); ????????????UnsubscribeEvents(); ????????????_valueTextBox?=?GetTemplateChild(TextBoxTemplateName)?as?TextBox; ????????????_repeatUp?=?GetTemplateChild(NumericUpTemplateName)?as?RepeatButton; ????????????_repeatDown?=?GetTemplateChild(NumericDownTemplateName)?as?RepeatButton; ????????????if?(_valueTextBox?==?null?||?_repeatUp?==?null?||?_repeatDown?==?null) ????????????{ ????????????????throw?new?NullReferenceException(string.Format("You?have?missed?to?specify?{0},?{1}?or?{2}?in?your?template",?NumericUpTemplateName,?NumericDownTemplateName,?TextBoxTemplateName)); ????????????} ????????????_repeatUp.PreviewMouseUp?+=?OnRepeatButtonPreviewMouseUp; ????????????_repeatDown.PreviewMouseUp?+=?OnRepeatButtonPreviewMouseUp; ????????????ToggleReadOnlyMode(IsReadOnly); ????????????OnValueChanged(Value,?Value); ????????} ????????protected?override?void?OnGotFocus(RoutedEventArgs?e) ????????{ ????????????base.OnGotFocus(e); ????????????if?(Focusable?&&?!IsReadOnly) ????????????{ ????????????????Focused(); ????????????????SelectAll(); ????????????} ????????} ????????protected?override?void?OnPreviewMouseWheel(MouseWheelEventArgs?e) ????????{ ????????????base.OnPreviewMouseWheel(e); ????????????if?(e.Delta?!=?0?&&?(IsFocused?||?_valueTextBox.IsFocused)) ????????????????ContinueChangeValue(e.Delta?>=?0,?false); ????????} ????????protected?override?void?OnPreviewKeyDown(KeyEventArgs?e) ????????{ ????????????base.OnPreviewKeyDown(e); ????????????switch?(e.Key) ????????????{ ????????????????case?Key.Enter: ????????????????????DealInputText(_valueTextBox.Text); ????????????????????SelectAll(); ????????????????????e.Handled?=?true; ????????????????????break; ????????????????case?Key.Up: ????????????????????ContinueChangeValue(true); ????????????????????e.Handled?=?true; ????????????????????break; ????????????????case?Key.Down: ????????????????????ContinueChangeValue(false); ????????????????????e.Handled?=?true; ????????????????????break; ????????????} ????????} ????????protected?override?void?OnPreviewKeyUp(KeyEventArgs?e) ????????{ ????????????base.OnPreviewKeyUp(e); ????????????switch?(e.Key) ????????????{ ????????????????case?Key.Down: ????????????????case?Key.Up: ????????????????????ResetInternal(); ????????????????????break; ????????????} ????????} ????????#endregion ????????#region?Event? ????????private?void?OnRepeatButtonPreviewMouseUp(object?sender,?MouseButtonEventArgs?e) ????????{ ????????????ResetInternal(); ????????} ????????private?void?OnPreviewMouseLeftButtonDown(object?sender,?MouseButtonEventArgs?e) ????????{ ????????????if?(Focusable?&&?!IsReadOnly?&&?!_valueTextBox.IsKeyboardFocusWithin) ????????????{ ????????????????e.Handled?=?true; ????????????????Focused(); ????????????????SelectAll(); ????????????} ????????} ????????private?void?OnTextBoxLostFocus(object?sender,?RoutedEventArgs?e) ????????{ ????????????var?tb?=?(TextBox)sender; ????????????DealInputText(tb.Text); ????????} ????????private?void?OnValueTextBoxPaste(object?sender,?DataObjectPastingEventArgs?e) ????????{ ????????????var?textBox?=?(TextBox)sender; ????????????var?textPresent?=?textBox.Text; ????????????if?(!e.SourceDataObject.GetDataPresent(DataFormats.Text,?true)) ????????????????return; ????????????var?text?=?e.SourceDataObject.GetData(DataFormats.Text)?as?string; ????????????var?newText?=?string.Concat(textPresent.Substring(0,?textBox.SelectionStart),?text,?textPresent.Substring(textBox.SelectionStart?+?textBox.SelectionLength)); ????????????double?number; ????????????if?(!double.TryParse(newText,?out?number)) ????????????????e.CancelCommand(); ????????} ????????#endregion ????????#region?Private ????????private?void?UnsubscribeEvents() ????????{ ????????????if?(_valueTextBox?!=?null) ????????????{ ????????????????_valueTextBox.LostFocus?-=?OnTextBoxLostFocus; ????????????????_valueTextBox.PreviewMouseLeftButtonDown?-=?OnPreviewMouseLeftButtonDown; ????????????????DataObject.RemovePastingHandler(_valueTextBox,?OnValueTextBoxPaste); ????????????} ????????????if?(_repeatUp?!=?null) ????????????????_repeatUp.PreviewMouseUp?-=?OnRepeatButtonPreviewMouseUp; ????????????if?(_repeatDown?!=?null) ????????????????_repeatDown.PreviewMouseUp?-=?OnRepeatButtonPreviewMouseUp; ????????} ????????private?void?Focused() ????????{ ????????????_valueTextBox?.Focus(); ????????} ????????private?void?SelectAll() ????????{ ????????????_valueTextBox?.SelectAll(); ????????} ????????private?void?DealInputText(string?inputText) ????????{ ????????????double?convertedValue; ????????????if?(double.TryParse(inputText,?out?convertedValue)) ????????????{ ????????????????if?(DoubleUtil.AreClose(Value,?convertedValue)) ????????????????{ ????????????????????InternalSetText(Value); ????????????????????return; ????????????????} ????????????????_isManual?=?true; ????????????????if?(convertedValue?>?Maximum) ????????????????{ ????????????????????if?(DoubleUtil.AreClose(Value,?Maximum)) ????????????????????????OnValueChanged(Value,?Value); ????????????????????else ????????????????????????Value?=?Maximum; ????????????????} ????????????????else?if?(convertedValue?<?Minimum) ????????????????{ ????????????????????if?(DoubleUtil.AreClose(Value,?Minimum)) ????????????????????????OnValueChanged(Value,?Value); ????????????????????else ????????????????????????Value?=?Minimum; ????????????????} ????????????????else ????????????????????Value?=?convertedValue; ????????????} ????????????else ????????????????InternalSetText(Value); ????????} ????????private?void?MoveFocus() ????????{ ????????????var?request?=?new?TraversalRequest((Keyboard.Modifiers?&?ModifierKeys.Shift)?==?ModifierKeys.Shift???FocusNavigationDirection.Previous?:?FocusNavigationDirection.Next); ????????????var?elementWithFocus?=?Keyboard.FocusedElement?as?UIElement; ????????????elementWithFocus?.MoveFocus(request); ????????} ????????private?void?ToggleReadOnlyMode(bool?isReadOnly) ????????{ ????????????if?(_valueTextBox?==?null) ????????????????return; ????????????if?(isReadOnly) ????????????{ ????????????????_valueTextBox.LostFocus?-=?OnTextBoxLostFocus; ????????????????_valueTextBox.PreviewMouseLeftButtonDown?-=?OnPreviewMouseLeftButtonDown; ????????????????DataObject.RemovePastingHandler(_valueTextBox,?OnValueTextBoxPaste); ????????????} ????????????else ????????????{ ????????????????_valueTextBox.LostFocus?+=?OnTextBoxLostFocus; ????????????????_valueTextBox.PreviewMouseLeftButtonDown?+=?OnPreviewMouseLeftButtonDown; ????????????????DataObject.AddPastingHandler(_valueTextBox,?OnValueTextBoxPaste); ????????????} ????????} ????????private?void?InternalSetText(double?newValue) ????????{ ????????????var?text?=?newValue.ToString(GetPrecisionFormat()); ????????????if?(_valueTextBox?!=?null?&&?!Equals(text,?_valueTextBox.Text)) ????????????????_valueTextBox.Text?=?text; ????????} ????????private?string?GetPrecisionFormat() ????????{ ????????????return?Precision.HasValue?==?false ??????????????????"g" ????????????????:?(Precision.Value?==?0 ??????????????????????"#0" ????????????????????:?("#0.0"?+?string.Join("",?Enumerable.Repeat("#",?Precision.Value?-?1)))); ????????} ????????private?void?CoerceValue(DependencyProperty?dp,?object?localValue) ????????{ ????????????SetCurrentValue(dp,?localValue); ????????????CoerceValue(dp); ????????} ????????private?double?CorrectPrecision(int??precision,?double?originValue) ????????{ ????????????return?Math.Round(originValue,?precision????0,?MidpointRounding.AwayFromZero); ????????} ????????private?void?ContinueChangeValue(bool?isIncrease,?bool?isContinue?=?true) ????????{ ????????????if?(IsReadOnly?||?!IsEnabled) ????????????????return; ????????????if?(isIncrease?&&?DoubleUtil.LessThan(Value,?Maximum)) ????????????{ ????????????????if?(!_isBusy?&&?isContinue) ????????????????{ ????????????????????_isBusy?=?true; ????????????????????if?(DisabledValueChangedWhileBusy) ????????????????????????_lastOldValue?=?Value; ????????????????} ????????????????_isManual?=?true; ????????????????Value?=?(double)CoerceValue(this,?Value?+?CalculateInterval(isContinue)); ????????????} ????????????if?(!isIncrease?&&?DoubleUtil.GreaterThan(Value,?Minimum)) ????????????{ ????????????????if?(!_isBusy?&&?isContinue) ????????????????{ ????????????????????_isBusy?=?true; ????????????????????if?(DisabledValueChangedWhileBusy) ????????????????????????_lastOldValue?=?Value; ????????????????} ????????????????_isManual?=?true; ????????????????Value?=?(double)CoerceValue(this,?Value?-?CalculateInterval(isContinue)); ????????????} ????????} ????????private?double?CalculateInterval(bool?isContinue?=?true) ????????{ ????????????if?(!Speedup?||?!isContinue) ????????????????return?Interval; ????????????if?(DoubleUtil.GreaterThan((_intervalValueSinceReset?+=?_internalLargeChange),?_internalLargeChange?*?100)) ????????????????_internalLargeChange?*=?10; ????????????return?_internalLargeChange; ????????} ????????private?void?ResetInternal() ????????{ ????????????_internalLargeChange?=?Interval; ????????????_intervalValueSinceReset?=?0; ????????????_isBusy?=?false; ????????????if?(_lastOldValue.HasValue) ????????????{ ????????????????_isManual?=?true; ????????????????OnValueChanged(_lastOldValue.Value,?Value); ????????????????_lastOldValue?=?null; ????????????} ????????} ????????private?void?InvalidateRequerySuggested(double?value) ????????{ ????????????if?(_repeatUp?==?null?||?_repeatDown?==?null) ????????????????return; ????????????if?(DoubleUtil.AreClose(value,?Maximum)?&&?_repeatUp.IsEnabled ???????????????||?DoubleUtil.AreClose(value,?Minimum)?&&?_repeatDown.IsEnabled) ????????????????CommandManager.InvalidateRequerySuggested(); ????????????else ????????????{ ????????????????if?(!_repeatUp.IsEnabled?||?!_repeatDown.IsEnabled) ????????????????????CommandManager.InvalidateRequerySuggested(); ????????????} ????????} ????????#endregion ????} }
2)新增 NumericBox.xaml
代碼如下:
- 上下按鈕部分使用了一個垂直的
Grid
,其中包含三個行定義。第一行是上按鈕,第二行是一個高度為1
的占位行,第三行是下按鈕。 - 上按鈕和下按鈕都是
RepeatButton
類型,并分別命名為PART_NumericUp
和PART_NumericDown
。它們分別與controls:NumericBox.IncreaseCommand
和controls:NumericBox.DecreaseCommand
命令關(guān)聯(lián)。 - 樣式的觸發(fā)器部分定義了一個觸發(fā)條件,當(dāng)
UpDownButtonsWidth
屬性的值為0
時,將隱藏上下按鈕。
<ResourceDictionary ????xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" ????xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" ????xmlns:controls="clr-namespace:WPFDevelopers.Controls"> ????<ResourceDictionary.MergedDictionaries> ????????<ResourceDictionary?Source="Basic/ControlBasic.xaml"?/> ????</ResourceDictionary.MergedDictionaries> ????<Style ????????x:Key="WD.NumericBox" ????????BasedOn="{StaticResource?WD.ControlBasicStyle}" ????????TargetType="{x:Type?controls:NumericBox}"> ????????<Setter?Property="ScrollViewer.HorizontalScrollBarVisibility"?Value="Disabled"?/> ????????<Setter?Property="ScrollViewer.VerticalScrollBarVisibility"?Value="Disabled"?/> ????????<Setter?Property="BorderThickness"?Value="1"?/> ????????<Setter?Property="BorderBrush"?Value="{DynamicResource?WD.BaseSolidColorBrush}"?/> ????????<Setter?Property="Background"?Value="{DynamicResource?WD.BackgroundSolidColorBrush}"?/> ????????<Setter?Property="HorizontalContentAlignment"?Value="Stretch"?/> ????????<Setter?Property="VerticalContentAlignment"?Value="Center"?/> ????????<Setter?Property="FocusVisualStyle"?Value="{x:Null}"?/> ????????<Setter?Property="Padding"?Value="{StaticResource?WD.DefaultPadding}"?/> ????????<Setter?Property="Template"> ????????????<Setter.Value> ????????????????<ControlTemplate?TargetType="{x:Type?controls:NumericBox}"> ????????????????????<controls:SmallPanel?Width="{TemplateBinding?Width}"?Height="{TemplateBinding?Height}"> ????????????????????????<Border ????????????????????????????x:Name="PART_Border" ????????????????????????????Background="{TemplateBinding?Background}" ????????????????????????????BorderBrush="{TemplateBinding?BorderBrush}" ????????????????????????????BorderThickness="{TemplateBinding?BorderThickness}" ????????????????????????????CornerRadius="{Binding?Path=(helpers:ElementHelper.CornerRadius),?RelativeSource={RelativeSource?TemplatedParent}}" ????????????????????????????SnapsToDevicePixels="{TemplateBinding?SnapsToDevicePixels}"> ????????????????????????????<Grid> ????????????????????????????????<Grid.ColumnDefinitions> ????????????????????????????????????<ColumnDefinition?/> ????????????????????????????????????<ColumnDefinition?Width="Auto"?/> ????????????????????????????????</Grid.ColumnDefinitions> ????????????????????????????????<TextBox ????????????????????????????????????x:Name="PART_TextBox" ????????????????????????????????????MinHeight="{TemplateBinding?MinHeight}" ????????????????????????????????????Padding="{TemplateBinding?Padding}" ????????????????????????????????????HorizontalAlignment="Stretch" ????????????????????????????????????VerticalAlignment="Center" ????????????????????????????????????HorizontalContentAlignment="{TemplateBinding?HorizontalContentAlignment}" ????????????????????????????????????VerticalContentAlignment="{TemplateBinding?VerticalContentAlignment}" ????????????????????????????????????Background="{x:Null}" ????????????????????????????????????BorderThickness="0" ????????????????????????????????????FocusVisualStyle="{x:Null}" ????????????????????????????????????Focusable="{TemplateBinding?Focusable}" ????????????????????????????????????FontFamily="{TemplateBinding?FontFamily}" ????????????????????????????????????FontSize="{TemplateBinding?FontSize}" ????????????????????????????????????Foreground="{TemplateBinding?Foreground}" ????????????????????????????????????HorizontalScrollBarVisibility="{TemplateBinding?ScrollViewer.HorizontalScrollBarVisibility}" ????????????????????????????????????InputMethod.IsInputMethodEnabled="False" ????????????????????????????????????IsReadOnly="{TemplateBinding?IsReadOnly}" ????????????????????????????????????IsTabStop="{TemplateBinding?IsTabStop}" ????????????????????????????????????SelectionBrush="{DynamicResource?WD.WindowBorderBrushSolidColorBrush}" ????????????????????????????????????SnapsToDevicePixels="{TemplateBinding?SnapsToDevicePixels}" ????????????????????????????????????Style="{x:Null}" ????????????????????????????????????TabIndex="{TemplateBinding?TabIndex}" ????????????????????????????????????TextAlignment="{TemplateBinding?TextAlignment}" ????????????????????????????????????VerticalScrollBarVisibility="{TemplateBinding?ScrollViewer.VerticalScrollBarVisibility}"?/> ????????????????????????????????<Grid?Grid.Column="1"?Width="{TemplateBinding?UpDownButtonsWidth}"> ????????????????????????????????????<Grid.RowDefinitions> ????????????????????????????????????????<RowDefinition?/> ????????????????????????????????????????<RowDefinition?Height="1"?/> ????????????????????????????????????????<RowDefinition?/> ????????????????????????????????????</Grid.RowDefinitions> ????????????????????????????????????<RepeatButton ????????????????????????????????????????x:Name="PART_NumericUp" ????????????????????????????????????????Grid.Row="0" ????????????????????????????????????????Margin="0,1,1,0" ????????????????????????????????????????Command="{x:Static?controls:NumericBox.IncreaseCommand}" ????????????????????????????????????????Delay="{TemplateBinding?Delay}" ????????????????????????????????????????IsTabStop="False" ????????????????????????????????????????Style="{StaticResource?WD.DefaultRepeatButton}"> ????????????????????????????????????????<controls:PathIcon?Kind="ChevronUp"?Style="{StaticResource?WD.MiniPathIcon}"?/> ????????????????????????????????????</RepeatButton> ????????????????????????????????????<RepeatButton ????????????????????????????????????????x:Name="PART_NumericDown" ????????????????????????????????????????Grid.Row="2" ????????????????????????????????????????Margin="0,0,1,1" ????????????????????????????????????????Command="{x:Static?controls:NumericBox.DecreaseCommand}" ????????????????????????????????????????Delay="{TemplateBinding?Delay}" ????????????????????????????????????????IsTabStop="False"> ????????????????????????????????????????<controls:PathIcon?Kind="ChevronDown"?Style="{StaticResource?WD.MiniPathIcon}"?/> ????????????????????????????????????</RepeatButton> ????????????????????????????????</Grid> ????????????????????????????</Grid> ????????????????????????</Border> ????????????????????</controls:SmallPanel> ????????????????????<ControlTemplate.Triggers> ????????????????????????<Trigger?Property="UpDownButtonsWidth"?Value="0"> ????????????????????????????<Setter?TargetName="PART_NumericDown"?Property="Visibility"?Value="Collapsed"?/> ????????????????????????????<Setter?TargetName="PART_NumericUp"?Property="Visibility"?Value="Collapsed"?/> ????????????????????????</Trigger> ????????????????????????<Trigger?Property="IsReadOnly"?Value="True"> ????????????????????????????<Setter?Property="Focusable"?Value="False"?/> ????????????????????????????<Setter?TargetName="PART_NumericDown"?Property="IsEnabled"?Value="False"?/> ????????????????????????????<Setter?TargetName="PART_NumericUp"?Property="IsEnabled"?Value="False"?/> ????????????????????????</Trigger> ????????????????????????<Trigger?Property="IsMouseOver"?Value="True"> ????????????????????????????<Setter?Property="BorderBrush"?Value="{DynamicResource?WD.PrimaryNormalSolidColorBrush}"?/> ????????????????????????</Trigger> ????????????????????</ControlTemplate.Triggers> ????????????????</ControlTemplate> ????????????</Setter.Value> ????????</Setter> ????</Style> ????<Style?BasedOn="{StaticResource?WD.NumericBox}"?TargetType="{x:Type?controls:NumericBox}"?/> </ResourceDictionary>
3)示例
代碼如下:
????????????<wd:NumericBox ????????????????Width="100" ????????????????Maximum="100" ????????????????Minimum="0"?/> ????????????<wd:NumericBox ????????????????Width="100" ????????????????Margin="10,0" ????????????????Maximum="1000" ????????????????Minimum="100" ????????????????UpDownButtonsWidth="0"?/> ????????????<wd:NumericBox?Width="100"?Precision="3"?/>
效果圖
以上就是基于WPF實(shí)現(xiàn)數(shù)字框控件的詳細(xì)內(nèi)容,更多關(guān)于WPF數(shù)字框控件的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#爬蟲基礎(chǔ)之HttpClient獲取HTTP請求與響應(yīng)
這篇文章介紹了C#使用HttpClient獲取HTTP請求與響應(yīng)的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-05-05C#實(shí)現(xiàn)身份證實(shí)名認(rèn)證接口的示例代碼
身份證實(shí)名認(rèn)證,即通過姓名和身份證號校驗(yàn)個人信息的匹配程度,廣泛應(yīng)用于金融、互聯(lián)網(wǎng)等多個領(lǐng)域,本文主要介紹了C#實(shí)現(xiàn)身份證實(shí)名認(rèn)證接口的示例代碼,感興趣的可以了解一下2024-09-09