WPF 数字 UpDown 控件在哪里?

进入第一个严肃的 WPF 项目。似乎有很多基本的控制都不见了。具体来说,我要找的是 Numeric UpDown 控件。我是不是错过了乐队发布会?真的不想写我自己的控件。

我不想使用 WindowsFormHost 并在其上放置一个 WinFormctl。我希望它是完全 WPF 没有任何遗留垃圾。

谢谢

203543 次浏览

我自己做的

Xaml

<Grid  Height="23" Margin="152,63,11,0" VerticalAlignment="Top">
<TextBox x:Name="txtNum" x:FieldModifier="private" Text="0" TextChanged="txtNum_TextChanged" Margin="3,2,13,3" />
<Button x:Name="cmdUp" x:FieldModifier="private" FontSize="10" Padding="0,-4,0,0" Content="▲" Width="10" Click="cmdUp_Click" Margin="33,2,1,13" />
<Button x:Name="cmdDown" x:FieldModifier="private" FontSize="10" Padding="0,-4,0,0" Content="▼" Width="10" Click="cmdDown_Click" Margin="33,12,1,3" />
</Grid>

以及后面的代码

private int _numValue = 0;


public int NumValue
{
get {  return _numValue; }
set
{
_numValue = value;
txtNum.Text = value.ToString();
}
}


public NumberUpDown()
{
InitializeComponent();
txtNum.Text = _numValue.ToString();
}


private void cmdUp_Click(object sender, RoutedEventArgs e)
{
NumValue++;
}


private void cmdDown_Click(object sender, RoutedEventArgs e)
{
NumValue--;
}


private void txtNum_TextChanged(object sender, TextChangedEventArgs e)
{
if (txtNum == null)
{
return;
}


if (!int.TryParse(txtNum.Text, out _numValue))
txtNum.Text = _numValue.ToString();
}

这是我自己的 UserControl 的例子,它具有向上和向下键捕获功能。

Xaml 代码:

<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="13" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="13" />
<RowDefinition Height="13" />
</Grid.RowDefinitions>
<TextBox Name="NUDTextBox"  Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" TextAlignment="Right" PreviewKeyDown="NUDTextBox_PreviewKeyDown" PreviewKeyUp="NUDTextBox_PreviewKeyUp" TextChanged="NUDTextBox_TextChanged"/>
<RepeatButton Name="NUDButtonUP"  Grid.Column="1" Grid.Row="0" FontSize="8" FontFamily="Marlett" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Click="NUDButtonUP_Click">5</RepeatButton>
<RepeatButton Name="NUDButtonDown"  Grid.Column="1" Grid.Row="1" FontSize="8"  FontFamily="Marlett" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Height="13" VerticalAlignment="Bottom" Click="NUDButtonDown_Click">6</RepeatButton>
</Grid>

还有密码:

public partial class NumericUpDown : UserControl
{
int minvalue = 0,
maxvalue = 100,
startvalue = 10;
public NumericUpDown()
{
InitializeComponent();
NUDTextBox.Text = startvalue.ToString();
}


private void NUDButtonUP_Click(object sender, RoutedEventArgs e)
{
int number;
if (NUDTextBox.Text != "") number = Convert.ToInt32(NUDTextBox.Text);
else number = 0;
if (number < maxvalue)
NUDTextBox.Text = Convert.ToString(number + 1);
}


private void NUDButtonDown_Click(object sender, RoutedEventArgs e)
{
int number;
if (NUDTextBox.Text != "") number = Convert.ToInt32(NUDTextBox.Text);
else number = 0;
if (number > minvalue)
NUDTextBox.Text = Convert.ToString(number - 1);
}


private void NUDTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{


if (e.Key == Key.Up)
{
NUDButtonUP.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
typeof(Button).GetMethod("set_IsPressed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(NUDButtonUP, new object[] { true });
}




if (e.Key == Key.Down)
{
NUDButtonDown.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
typeof(Button).GetMethod("set_IsPressed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(NUDButtonDown, new object[] { true });
}
}


private void NUDTextBox_PreviewKeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Up)
typeof(Button).GetMethod("set_IsPressed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(NUDButtonUP, new object[] { false });


if (e.Key == Key.Down)
typeof(Button).GetMethod("set_IsPressed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(NUDButtonDown, new object[] { false });
}


private void NUDTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
int number = 0;
if (NUDTextBox.Text!="")
if (!int.TryParse(NUDTextBox.Text, out number)) NUDTextBox.Text = startvalue.ToString();
if (number > maxvalue)  NUDTextBox.Text = maxvalue.ToString();
if (number < minvalue) NUDTextBox.Text = minvalue.ToString();
NUDTextBox.SelectionStart = NUDTextBox.Text.Length;


}


}
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:numericButton2">




<Style TargetType="{x:Type local:NumericUpDown}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:NumericUpDown}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<RepeatButton Grid.Row="0" Name="Part_UpButton"/>
<ContentPresenter Grid.Row="1"></ContentPresenter>
<RepeatButton Grid.Row="2" Name="Part_DownButton"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>


<Window x:Class="numericButton2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:numericButton2"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:NumericUpDown Margin="181,94,253,161" x:Name="ufuk" StepValue="4" Minimum="0" Maximum="20">
</local:NumericUpDown>
<TextBlock Margin="211,112,279,0" Text="{Binding ElementName=ufuk, Path=Value}" Height="20" VerticalAlignment="Top"></TextBlock>
</Grid>
</Window>
public class NumericUpDown : Control
{
private RepeatButton _UpButton;
private RepeatButton _DownButton;
public readonly static DependencyProperty MaximumProperty;
public readonly static DependencyProperty MinimumProperty;
public readonly static DependencyProperty ValueProperty;
public readonly static DependencyProperty StepProperty;
static NumericUpDown()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(NumericUpDown), new FrameworkPropertyMetadata(typeof(NumericUpDown)));
MaximumProperty = DependencyProperty.Register("Maximum", typeof(int), typeof(NumericUpDown), new UIPropertyMetadata(10));
MinimumProperty = DependencyProperty.Register("Minimum", typeof(int), typeof(NumericUpDown), new UIPropertyMetadata(0));
StepProperty = DependencyProperty.Register("StepValue", typeof(int), typeof(NumericUpDown), new FrameworkPropertyMetadata(5));
ValueProperty = DependencyProperty.Register("Value", typeof(int), typeof(NumericUpDown), new FrameworkPropertyMetadata(0));
}
#region DpAccessior
public int Maximum
{
get { return (int)GetValue(MaximumProperty); }
set { SetValue(MaximumProperty, value); }
}
public int Minimum
{
get { return (int)GetValue(MinimumProperty); }
set { SetValue(MinimumProperty, value); }
}
public int Value
{
get { return (int)GetValue(ValueProperty); }
set { SetCurrentValue(ValueProperty, value); }
}
public int StepValue
{
get { return (int)GetValue(StepProperty); }
set { SetValue(StepProperty, value); }
}
#endregion
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_UpButton = Template.FindName("Part_UpButton", this) as RepeatButton;
_DownButton = Template.FindName("Part_DownButton", this) as RepeatButton;
_UpButton.Click += _UpButton_Click;
_DownButton.Click += _DownButton_Click;
}


void _DownButton_Click(object sender, RoutedEventArgs e)
{
if (Value > Minimum)
{
Value -= StepValue;
if (Value < Minimum)
Value = Minimum;
}
}


void _UpButton_Click(object sender, RoutedEventArgs e)
{
if (Value < Maximum)
{
Value += StepValue;
if (Value > Maximum)
Value = Maximum;
}
}


}

在 WPF 中使用 VerticalScrollBarTextBlock控件。在后面的代码中,添加以下代码:

在构造函数中,为滚动条定义一个事件处理程序:

scrollBar1.ValueChanged += new RoutedPropertyChangedEventHandler<double>(scrollBar1_ValueChanged);
scrollBar1.Minimum = 0;
scrollBar1.Maximum = 1;
scrollBar1.SmallChange = 0.1;

然后在事件处理程序中,添加:

void scrollBar1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
FteHolderText.Text = scrollBar1.Value.ToString();
}

下面是我的代码的原始代码片段... ... 进行必要的更改. . :)

public NewProjectPlan()
{
InitializeComponent();


this.Loaded += new RoutedEventHandler(NewProjectPlan_Loaded);


scrollBar1.ValueChanged += new RoutedPropertyChangedEventHandler<double>(scrollBar1_ValueChanged);
scrollBar1.Minimum = 0;
scrollBar1.Maximum = 1;
scrollBar1.SmallChange = 0.1;


// etc...
}


void scrollBar1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
FteHolderText.Text = scrollBar1.Value.ToString();
}

只需使用 < a href = “ https://github.com/xceedsoftware/wpftoolkit”rel = “ norefrer”> Extended. Wpf. Toolkit 中的 IntegerUpDown控件 你可以这样使用它:

  1. 在 XAML 中添加以下命名空间:

    xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"

  2. 在您希望控件使用的 XAML 中:

    <xctk:IntegerUpDown Name="myUpDownControl" />

您可以使用 NumericUpDown 控件作为 WPFControls库的一部分,用于我编写的 WPF。

我有一个天真但有用的解决办法。 密码如下:

<Grid Name="TVGrid" Background="#7F000000">  <ScrollBar Background="Black" Orientation="Vertical" Height="35" HorizontalAlignment="Left" Margin="215,254,0,0" Minimum="0" Maximum="10" LargeChange="10" Value="{Binding ElementName=channeltext2, Path=Text}" x:Name="scroll" VerticalAlignment="Top" Width="12" RenderTransformOrigin="0.5,0.5" ValueChanged="scroll_ValueChanged" >
<ScrollBar.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="-180"/>
<TranslateTransform/>
</TransformGroup>
</ScrollBar.RenderTransform>
</ScrollBar>
<TextBox Name="channeltext" HorizontalContentAlignment="Center" FontSize="20"  Background="Black" Foreground="White" Height="35" HorizontalAlignment="Left" Margin="147,254,0,0" VerticalAlignment="Top" Width="53" Text="0" />
<TextBox Name="channeltext2" Visibility="Hidden" HorizontalContentAlignment="Center" FontSize="20"  Background="Black" Foreground="White" Height="35" HorizontalAlignment="Left" Margin="147,254,0,0" VerticalAlignment="Top" Width="53" Text="0" />  </Grid>

给出的答案是可以的。但是,我希望按钮自动隐藏,当鼠标离开控制。下面是我根据上面 Vercin答案编写的代码:

风格

<Style TargetType="{x:Type v:IntegerTextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type v:IntegerTextBox}">
<Grid Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBox Name="tbmain" Grid.ColumnSpan="2" Grid.RowSpan="2"
Text="{Binding Value, Mode=TwoWay, NotifyOnSourceUpdated=True,
NotifyOnValidationError=True, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type v:IntegerTextBox}}}"
Style="{StaticResource ValidationStyle}" />
<RepeatButton Name="PART_UpButton" BorderThickness="0" Grid.Column="1" Grid.Row="0"
Width="13" Background="Transparent">
<Path Fill="Black" Data="M 0 3 L 6 3 L 3 0 Z"/>
</RepeatButton>
<RepeatButton Name="PART_DownButton" BorderThickness="0" Grid.Column="1" Grid.Row="1"
Width="13" Background="Transparent">
<Path Fill="Black" Data="M 0 0 L 3 3 L 6 0 Z"/>
</RepeatButton>


</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"  Value="False">
<Setter Property="Visibility" TargetName="PART_UpButton" Value="Collapsed"/>
<Setter Property="Visibility" TargetName="PART_DownButton" Value="Collapsed"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

密码

public partial class IntegerTextBox : UserControl
{
public IntegerTextBox()
{
InitializeComponent();
}


public int Maximum
{
get { return (int)GetValue(MaximumProperty); }
set { SetValue(MaximumProperty, value); }
}
public readonly static DependencyProperty MaximumProperty = DependencyProperty.Register(
"Maximum", typeof(int), typeof(IntegerTextBox), new UIPropertyMetadata(int.MaxValue));






public int Minimum
{
get { return (int)GetValue(MinimumProperty); }
set { SetValue(MinimumProperty, value); }
}
public readonly static DependencyProperty MinimumProperty = DependencyProperty.Register(
"Minimum", typeof(int), typeof(IntegerTextBox), new UIPropertyMetadata(int.MinValue));




public int Value
{
get { return (int)GetValue(ValueProperty); }
set { SetCurrentValue(ValueProperty, value); }
}
public readonly static DependencyProperty ValueProperty = DependencyProperty.Register(
"Value", typeof(int), typeof(IntegerTextBox), new UIPropertyMetadata(0, (o,e)=>
{
IntegerTextBox tb = (IntegerTextBox)o;
tb.RaiseValueChangedEvent(e);
}));


public event EventHandler<DependencyPropertyChangedEventArgs> ValueChanged;
private void RaiseValueChangedEvent(DependencyPropertyChangedEventArgs e)
{
ValueChanged?.Invoke(this, e);
}




public int Step
{
get { return (int)GetValue(StepProperty); }
set { SetValue(StepProperty, value); }
}
public readonly static DependencyProperty StepProperty = DependencyProperty.Register(
"Step", typeof(int), typeof(IntegerTextBox), new UIPropertyMetadata(1));






RepeatButton _UpButton;
RepeatButton _DownButton;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_UpButton = Template.FindName("PART_UpButton", this) as RepeatButton;
_DownButton = Template.FindName("PART_DownButton", this) as RepeatButton;
_UpButton.Click += btup_Click;
_DownButton.Click += btdown_Click;
}




private void btup_Click(object sender, RoutedEventArgs e)
{
if (Value < Maximum)
{
Value += Step;
if (Value > Maximum)
Value = Maximum;
}
}


private void btdown_Click(object sender, RoutedEventArgs e)
{
if (Value > Minimum)
{
Value -= Step;
if (Value < Minimum)
Value = Minimum;
}
}


}

为一直回答9年来的问题而道歉。

我听从了“迈克尔的回答,它奏效了。”。

我作为用户控件这样做,在这里我可以像控件元素一样拖放。我使用来自 Nuget 的材质设计主题来获得雪佛龙图标和按钮的涟漪效果。

正在运行的修改后的 NumericUpDown 如下所示:-

enter image description here

用户控件的代码:-

TemplateNumericUpDown.xaml

<UserControl x:Class="UserControlTemplate.TemplateNumericUpDown"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:UserControlTemplate"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d" MinHeight="48">
<Grid Background="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="60"/>
</Grid.ColumnDefinitions>
<TextBox x:Name="txtNum" x:FieldModifier="private" Text="{Binding Path=NumValue}" TextChanged="TxtNum_TextChanged" FontSize="36" BorderThickness="0" VerticalAlignment="Center" Padding="5,0"/>
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="30*"/>
<RowDefinition Height="30*"/>
</Grid.RowDefinitions>
<Grid Background="#FF673AB7">
<Viewbox HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Height="Auto" Width="Auto">
<materialDesign:PackIcon Kind="ChevronUp" Foreground="White" Height="32.941" Width="32"/>
</Viewbox>
<Button x:Name="cmdUp" x:FieldModifier="private" Click="CmdUp_Click" Height="Auto" BorderBrush="{x:Null}" Background="{x:Null}"/>
</Grid>
<Grid Grid.Row="1" Background="#FF673AB7">
<Viewbox HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Height="Auto" Width="Auto">
<materialDesign:PackIcon Kind="ChevronDown" Foreground="White" Height="32.942" Width="32"/>
</Viewbox>
<Button x:Name="cmdDown" x:FieldModifier="private" Click="CmdDown_Click" Height="Auto" BorderBrush="{x:Null}" Background="{x:Null}"/>
</Grid>
</Grid>
</Grid>
</UserControl>

Templatenumericupdown.cs

using System.Windows;
using System.Windows.Controls;


namespace UserControlTemplate
{
/// <summary>
/// Interaction logic for TemplateNumericUpDown.xaml
/// </summary>
public partial class TemplateNumericUpDown : UserControl
{
private int _numValue = 0;
public TemplateNumericUpDown()
{
InitializeComponent();
txtNum.Text = _numValue.ToString();
}
public int NumValue
{
get { return _numValue; }
set
{
if (value >= 0)
{
_numValue = value;
txtNum.Text = value.ToString();
}
}
}


private void CmdUp_Click(object sender, RoutedEventArgs e)
{
NumValue++;
}


private void CmdDown_Click(object sender, RoutedEventArgs e)
{
NumValue--;
}


private void TxtNum_TextChanged(object sender, TextChangedEventArgs e)
{
if (txtNum == null)
{
return;
}


if (!int.TryParse(txtNum.Text, out _numValue))
txtNum.Text = _numValue.ToString();
}
}
}

在 MyPageDesign.xaml 上,拖放创建的用户控件将具有 <UserControlTemplate:TemplateNumericUpDown HorizontalAlignment="Left" Height="100" VerticalAlignment="Top" Width="100"/>

enter image description here

为了从模板中获取值,我使用

string Value1 = JournalNumStart.NumValue;
string Value2 = JournalNumEnd.NumValue;

我还没有很好的技巧来绑定基于 FontSize 元素的控件的 Height,所以我在用户控件中手动设置了页面的字体大小。

* * 注意:-我已经将程序中的“ Archive”名称更改为 Archive =)

下面是另一个开源控件,它有许多不同的输入方法(鼠标拖动、鼠标滚轮、光标键、文本框编辑) ,支持许多数据类型和用例:

Https://github.com/dirkster99/numericupdownlib

只是一个务实的例子:

- 右键单击您的 工程项目(解决方案下) ,选择“管理 nuget 软件包...”

- 在选单按 浏览选项卡搜寻「 wpftoolkit 」 ,选择「 Extended.Wpf.Toolkit

- 安装它!

- 在用户控件 工具箱中右键单击,选择“ Add Tab. .”并将其命名为“ WPF Toolkit”

- 右击新的“ WPF 工具箱”选项卡,选择“选择项目...”

- 在菜单中点击“浏览...”按钮,查找 nugets DLL 文件夹,选择所有 “ ...\packages\Extended.Wpf.Toolkit.3.5.0\lib\net40\*.dll

忽略关于某些 DLL 可能不包含用户控件的警告!

准备:)

进入你项目的 NugetPackage 管理器-> 浏览并搜索 mahApps。Metro-> 将软件包安装到您的项目中。您将看到 Reference add: MahApps。警察。 然后在 XAML 代码中添加:

"xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"

要使用对象的位置添加:

<mah:NumericUpDown x:Name="NumericUpDown" ... />

享受对象的完全可扩展性(绑定、触发器等等... ...)。

让我们来享受一些滑稽的东西:
这里是一个 SliderStyle作为一个 NumericUpDown,简单,易于使用,没有任何隐藏的代码或第三方库。

<Style TargetType="{x:Type Slider}">
<Style.Resources>
<Style x:Key="RepeatButtonStyle" TargetType="{x:Type RepeatButton}">
<Setter Property="Focusable" Value="false" />
<Setter Property="IsTabStop" Value="false" />
<Setter Property="Padding" Value="0" />
<Setter Property="Width" Value="20" />
</Style>
</Style.Resources>
<Setter Property="Stylus.IsPressAndHoldEnabled" Value="false" />
<Setter Property="SmallChange" Value="1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Slider}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox Grid.RowSpan="2" Height="Auto"
Margin="0" Padding="0"
VerticalAlignment="Stretch" VerticalContentAlignment="Center"
Text="{Binding Value, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}">
<TextBox.InputBindings>
<KeyBinding Gesture="Up" Command="{x:Static Slider.IncreaseSmall}" />
<KeyBinding Gesture="Down" Command="{x:Static Slider.DecreaseSmall}" />
<KeyBinding Gesture="PageUp" Command="{x:Static Slider.IncreaseLarge}" />
<KeyBinding Gesture="PageDown" Command="{x:Static Slider.DecreaseLarge}" />
</TextBox.InputBindings>
</TextBox>
<RepeatButton Grid.Row="0" Grid.Column="1"
Command="{x:Static Slider.IncreaseSmall}"
Style="{StaticResource RepeatButtonStyle}">
<Path Data="M4,0 L0,4 8,4 Z" Fill="Black" />
</RepeatButton>
<RepeatButton Grid.Row="1" Grid.Column="1"
Command="{x:Static Slider.DecreaseSmall}"
Style="{StaticResource RepeatButtonStyle}">
<Path Data="M0,0 L4,4 8,0 Z" Fill="Black" />
</RepeatButton>
<Border x:Name="TrackBackground" Visibility="Collapsed">
<Rectangle x:Name="PART_SelectionRange" Visibility="Collapsed" />
</Border>
<Thumb x:Name="Thumb" Visibility="Collapsed" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

如果你确实想对 TextBox应用输入限制,试试这个:

public static class InputLimit
{
public static string GetDecimalValueProxy(TextBox obj) => (string)obj.GetValue(DecimalValueProxyProperty);


public static void SetDecimalValueProxy(TextBox obj, string value) => obj.SetValue(DecimalValueProxyProperty, value);


// Using a DependencyProperty as the backing store for DecimalValueProxy.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty DecimalValueProxyProperty =
DependencyProperty.RegisterAttached("DecimalValueProxy", typeof(string), typeof(InputLimit),
new FrameworkPropertyMetadata("0", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, null, CoerceDecimalValueProxy));


private static object CoerceDecimalValueProxy(DependencyObject d, object baseValue)
{
if (decimal.TryParse(baseValue as string, out _)) return baseValue;
return DependencyProperty.UnsetValue;
}
}

并将 xaml TextBox部分修改为:

<TextBox Grid.RowSpan="2" Height="Auto"
Margin="0" Padding="0"
VerticalAlignment="Stretch" VerticalContentAlignment="Center"
local:InputLimit.DecimalValueProxy="{Binding Value, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}"
Text="{Binding RelativeSource={RelativeSource Self}, Path=(local:InputLimit.DecimalValueProxy), Mode=TwoWay}">

编辑:
但是上面的代码有一个讨厌的错误..。
看看代码:

Text="{Binding Value, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}"

TextBox会在失去焦点后更新值,但如果在 Binding中添加 UpdateSourceTrigger=PropertyChanged,则不能键入 dot (.)进入 TextBox

您可以使用下一个转换器代码来修复它:

public class SafeDotConverter : MarkupExtension, IValueConverter
{
private bool hasDot;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var dbl = (double)value;
if (hasDot && Math.Truncate(dbl) == dbl)
{
return $"{dbl}.";
}
return value.ToString();
}


public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is string str)
{
hasDot = str.EndsWith(".");


if (double.TryParse(str, out var val))
return val;
}
return DependencyProperty.UnsetValue;
}


public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}

在 Xaml 中使用:

Text="{Binding Value, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={local:SafeDotConverter}}"

这是对另一个答案的修改,但带有绑定支持

<UserControl x:Class="YourNamespace.Controls.NumericUpDown"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:NetReactorLM.Desktop.Controls"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid  VerticalAlignment="Top">
<TextBox x:Name="txtNum" x:FieldModifier="private" Text="0" TextChanged="txtNum_TextChanged" Margin="3,2,13,3" />
<Button x:Name="cmdUp" x:FieldModifier="private" FontSize="10" Padding="0,-4,0,0" Content="▲" Width="10" Click="cmdUp_Click" Margin="33,2,1,13" />
<Button x:Name="cmdDown" x:FieldModifier="private" FontSize="10" Padding="0,-4,0,0" Content="▼" Width="10" Click="cmdDown_Click" Margin="33,12,1,3" />
</Grid>
</UserControl>



using System.Windows;
using System.Windows.Controls;


namespace YourNamespace.Controls
{
public partial class NumericUpDown : UserControl
{


public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
"Value", typeof(int), typeof(NumericUpDown), new PropertyMetadata(default(int)));


public int Value
{
get { return (int) GetValue(ValueProperty); }
set
{
SetValue(ValueProperty, value);
txtNum.Text = value.ToString();
}
}
        

public NumericUpDown()
{
InitializeComponent();
txtNum.Text = Value.ToString();
}


private void cmdUp_Click(object sender, RoutedEventArgs e)
{
Value++;
}


private void cmdDown_Click(object sender, RoutedEventArgs e)
{
Value--;
}


private void txtNum_TextChanged(object sender, TextChangedEventArgs e)
{
if (txtNum == null)
{
return;
}


if (!int.TryParse(txtNum.Text, out var val))
{
Value = val;
txtNum.Text = val.ToString();
}
}
}
}

免费版本的 Extended.Wpf.Toolkit 不支持.net 核心和.net

您可以使用 HandyControl,它有一个 NumericUpDown 控件,在 Wpf 和.net 5中运行良好。

Https://github.com/handyorg/handycontrol

你可以使用“ NumericUpDown”。

<mah:NumericUpDown MinWidth="70" Height="35" Minimum="0" Maximum="10000" Interval="1" />

这是链接 Https://mahapps.com/docs/controls/numericupdown