基于WPF实现数字框控件
作者:WPF开发者
这篇文章主要介绍了如何利用WPF实现数字框控件,文中的示例代码讲解详细,对我们学习或工作有一定的帮助,需要的小伙伴可以参考一下
WPF 实现数字框控件
框架使用.NET4 至 .NET6
;
Visual Studio 2022
;
实现代码
1)新增 NumericBox.cs
代码如下:
OnPreviewKeyDown
方法:
- 处理
Enter
键:调用DealInputText
方法处理输入文本,选择所有文本,并标记事件为已处理。 - 处理向上箭头键:调用
ContinueChangeValue
方法增加NumericBox
值,并标记事件为已处理。 - 处理向下箭头键:调用
ContinueChangeValue
方法减少NumericBox
值,并标记事件为已处理。
OnPreviewKeyUp
方法:
处理释放的向上箭头键或向下箭头键:调用 ResetInternal
方法重置 NumericBox
内部状态。
尝试将输入的文本转换为 double
类型的数值。
如果转换成功:
检查转换后的值与当前值是否非常接近,如果是,则不做任何操作。
否则,根据转换后的值和最大值、最小值进行比较:
如果大于最大值,则将值设置为最大值。
如果小于最小值,则将值设置为最小值。
否则,将值设置为转换后的值。
如果转换失败,则将当前值设置回文本框。
Precision
可输入多少小数位。
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
命令关联。 - 样式的触发器部分定义了一个触发条件,当
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实现数字框控件的详细内容,更多关于WPF数字框控件的资料请关注脚本之家其它相关文章!