主要功能:
1)、左右RepeatedButton;
2)、支持最小,最大值以及输入的检测,回滚;
3)、支持每次减少/增加的值幅度大小;
4)、支持前缀Label,长度,可见性。
第1步、构造控件的具体样式
完整XAML代码如下:
<UserControl x:Class="WpfUserControlApp11.MyNumUpDown"
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:WpfUserControlApp11"
mc:Ignorable="d"
d:DesignHeight="36" d:DesignWidth="100">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" MinWidth="0"/>
<ColumnDefinition Width="6*" MinWidth="20"/>
<ColumnDefinition Width="9*" MinWidth="36"/>
<ColumnDefinition Width="6*" MinWidth="20"/>
</Grid.ColumnDefinitions>
<Label
Name="myNumLabelName"
Grid.Row="0"
Grid.Column="0"
Margin="0"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Foreground="Black"
FontSize="12" />
<RepeatButton Grid.Column="1" x:Name="btnSub" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Content=" - " Margin="0 0 0 0" Click="btnSubClick" FontSize="20"
ClickMode="Press"
Delay="500"
Interval="80">
<RepeatButton.Style>
<Style TargetType="RepeatButton">
<Setter Property="Background" Value="#DDDDDD"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Border BorderBrush="{TemplateBinding Control.BorderBrush}" Background="{TemplateBinding Background}" BorderThickness="0.5 0.5 0 0.5" CornerRadius="6 0 0 6">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#87CEFA"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#30BCFA"/>
<Setter Property="Foreground" Value="#FFFFFF"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="WhiteSmoke"/>
</Trigger>
</Style.Triggers>
</Style>
</RepeatButton.Style>
</RepeatButton>
<TextBox
Grid.Column="2"
x:Name="tbContent"
Margin="0 0 0 0"
FontSize="12"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
TextChanged="tbContentTextChanged"
GotFocus="tbContentGotFocus"
LostFocus="tbCntLostFocus"
Text="0">
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="Background" Value="#FFFFFF"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#F0F8FF"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="#FFFFFF"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<RepeatButton Grid.Column="3" x:Name="btnAdd" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Content=" + " Margin="0 0 0 0" Click="btnAddClick" FontSize="20"
ClickMode="Press"
Delay="500"
Interval="80">
<RepeatButton.Style>
<Style TargetType="RepeatButton">
<Setter Property="Background" Value="#DDDDDD"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Border BorderBrush="{TemplateBinding Control.BorderBrush}" Background="{TemplateBinding Background}" BorderThickness="0 0.5 0.5 0.5" CornerRadius="0 6 6 0">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#87CEFA"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#30BCFA"/>
<Setter Property="Foreground" Value="#FFFFFF"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="WhiteSmoke"/>
</Trigger>
</Style.Triggers>
</Style>
</RepeatButton.Style>
</RepeatButton>
</Grid>
</UserControl>
第2步、控件的业务逻辑CS代码
完整的C#代码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfUserControlApp11
{
/// <summary>
/// MyNumUpDown.xaml 的交互逻辑
/// </summary>
public partial class MyNumUpDown : UserControl
{
/// <summary>
/// 当前值
/// </summary>
private decimal AvaliableVal = 0;
/// <summary>
/// Sync Resource
/// </summary>
private static object lockObj = new object();
public MyNumUpDown()
{
InitializeComponent();
}
/// <summary>
/// label 显示内容
/// </summary>
public string LabeContent
{
get { return GetValue(LabeContentProperty).ToString(); }
set { SetValue(LabeContentProperty, value); }
}
/// <summary>
/// 最小值
/// </summary>
public decimal MinValue
{
get { return Convert.ToDecimal(GetValue(MinValueProperty)); }
set { SetValue(MinValueProperty, value); }
}
/// <summary>
/// 最大值
/// </summary>
public decimal MaxValue
{
get { return Convert.ToDecimal(GetValue(MaxValueProperty)); }
set
{
SetValue(MaxValueProperty, value);
}
}
/// <summary>
/// 默认值
/// </summary>
public decimal DefaultValue
{
get { return Convert.ToDecimal(GetValue(DefaultValueProperty)); }
set
{
SetValue(DefaultValueProperty, value);
NumericValue = DefaultValue;
}
}
/// <summary>
/// 是否整数
/// </summary>
public bool IsInteger
{
get { return Convert.ToBoolean(GetValue(IsIntegerProperty)); }
set { SetValue(IsIntegerProperty, value); }
}
/// <summary>
/// 步长
/// </summary>
public decimal OffsetValue
{
get { return Convert.ToDecimal(GetValue(OffsetValueProperty)); }
set { SetValue(OffsetValueProperty, value); }
}
/// <summary>
/// 输入框值
/// </summary>
public decimal NumericValue
{
get { return Convert.ToDecimal(GetValue(NumericValueProperty)); }
set
{
SetValue(NumericValueProperty, value);
}
}
/// <summary>
/// 左侧的Label的宽度
/// </summary>
public double LabelWidth
{
get { return Convert.ToDouble(GetValue(LabelWidthValueProperty)); }
set { SetValue(LabelWidthValueProperty, value); }
}
/// <summary>
/// 标签的可见性
/// </summary>
public string LabelVisibility
{
get { return Convert.ToString(GetValue(LabelVisibilityValueProperty)); }
set { SetValue(LabelVisibilityValueProperty, value); }
}
public static readonly DependencyProperty LabeContentProperty =
DependencyProperty.Register("LabeContent",
typeof(string),
typeof(MyNumUpDown),
new PropertyMetadata("", new PropertyChangedCallback(LabelContentCallback))
);
private static void LabelContentCallback(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
MyNumUpDown control = obj as MyNumUpDown;
control.myNumLabelName.Content = e.NewValue.ToString();
}
public static readonly DependencyProperty MinValueProperty =
DependencyProperty.Register("MinValue",
typeof(decimal),
typeof(MyNumUpDown),
new PropertyMetadata(-1m, null)
);
public static readonly DependencyProperty MaxValueProperty =
DependencyProperty.Register("MaxValue",
typeof(decimal),
typeof(MyNumUpDown),
new PropertyMetadata(-1m, new PropertyChangedCallback(MaxValueChangedCallback))
);
public static readonly DependencyProperty DefaultValueProperty =
DependencyProperty.Register("DefaultValue",
typeof(decimal),
typeof(MyNumUpDown)
);
public static readonly DependencyProperty IsIntegerProperty =
DependencyProperty.Register("IsInteger",
typeof(bool),
typeof(MyNumUpDown), new PropertyMetadata(false)
);
public static readonly DependencyProperty OffsetValueProperty =
DependencyProperty.Register("OffsetValue",
typeof(decimal),
typeof(MyNumUpDown), new PropertyMetadata(1m)
);
public static readonly DependencyProperty NumericValueProperty =
DependencyProperty.Register("NumericValue",
typeof(decimal),
typeof(MyNumUpDown),
new PropertyMetadata(new PropertyChangedCallback(NumericValueChangedCallback))
);
public static readonly DependencyProperty LabelWidthValueProperty =
DependencyProperty.Register("LabelWidth",
typeof(double),
typeof(MyNumUpDown),
new PropertyMetadata(0.0, new PropertyChangedCallback(LabelWidthCallback))
);
public static readonly DependencyProperty LabelVisibilityValueProperty =
DependencyProperty.Register("LabelVisibility",
typeof(string),
typeof(MyNumUpDown),
new PropertyMetadata("Visible", new PropertyChangedCallback(LabelVisibilityCallback))
);
private static void LabelWidthCallback(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
MyNumUpDown control = obj as MyNumUpDown;
control.myNumLabelName.Width = double.Parse(string.IsNullOrEmpty(e.NewValue.ToString()) ? "0" : e.NewValue.ToString());
}
private static void LabelVisibilityCallback(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
MyNumUpDown control = obj as MyNumUpDown;
string visi = e.NewValue.ToString();
if (visi.Equals(Visibility.Visible.ToString()))
control.myNumLabelName.Visibility = Visibility.Visible;
else if (visi.Equals(Visibility.Hidden.ToString()))
control.myNumLabelName.Visibility = Visibility.Hidden;
else
control.myNumLabelName.Visibility = Visibility.Collapsed;
}
private static void MaxValueChangedCallback(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
MyNumUpDown control = obj as MyNumUpDown;
control.tbContent.MaxLength = e.NewValue.ToString().Length;
}
private static void NumericValueChangedCallback(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
MyNumUpDown control = obj as MyNumUpDown;
control.AvaliableVal = Convert.ToDecimal(e.NewValue);
control.tbContent.Text = e.NewValue.ToString();
control.tbContent.SelectionStart = control.tbContent.Text.Length;
}
/// <summary>
/// 增加按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnAddClick(object sender, RoutedEventArgs e)
{
decimal offsetValue = OffsetValue;
AvaliableVal = Convert.ToDecimal(tbContent.Text);
decimal newValue;
if (AvaliableVal > MaxValue)
{
NumericValue = MaxValue;
return;
}
if (AvaliableVal + offsetValue > MaxValue)
{
NumericValue = MaxValue;
return;
}
newValue = AvaliableVal + offsetValue;
if (newValue < MinValue)
{
NumericValue = MinValue;
return;
}
if (IsInteger)
newValue = decimal.Parse(newValue.ToString("0"));
else
newValue = decimal.Parse(newValue.ToString("0.######"));
tbContent.Text = newValue.ToString();
NumericValue = newValue;
}
/// <summary>
/// 减少按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSubClick(object sender, RoutedEventArgs e)
{
AvaliableVal = Convert.ToDecimal(tbContent.Text);
if (AvaliableVal < MinValue)
{
NumericValue = MinValue;
return;
}
if (AvaliableVal - OffsetValue < MinValue)
{
NumericValue = MinValue;
return;
}
if (AvaliableVal > MaxValue)
{
NumericValue = MaxValue;
return;
}
decimal newValue;
newValue = AvaliableVal - OffsetValue;
if (IsInteger)
newValue = decimal.Parse(newValue.ToString("0"));
else
newValue = decimal.Parse(newValue.ToString("0.######"));
tbContent.Text = newValue.ToString();
NumericValue = newValue;
}
/// <summary>
/// 获取焦点
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void tbContentGotFocus(object sender, RoutedEventArgs e)
{
TextBox tb = sender as System.Windows.Controls.TextBox;
this.AvaliableVal = Convert.ToDecimal(tb.Text);
}
/// <summary>
/// 是否数字
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
private bool IsNumber(string input)
{
string pattern = "^-?\\d+$|^(-?\\d+)(\\.\\d+)?$";
Regex regex = new Regex(pattern);
return regex.IsMatch(input);
}
/// <summary>
/// 是否整数
/// </summary>
/// <param name="strNumber"></param>
/// <returns></returns>
private bool IsWholeNumber(string strNumber)
{
Regex g = new Regex(@"^[0-9]\d*$");
return g.IsMatch(strNumber);
}
/// <summary>
/// 数字Text变动Event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void tbContentTextChanged(object sender, TextChangedEventArgs e)
{
lock (lockObj)
{
TextBox tb = sender as TextBox;
if (tb != null)
{
bool isNumeric = IsNumber(tb.Text);
if (isNumeric)
{
var vv = Convert.ToDecimal(tb.Text);
if (vv > MaxValue && MaxValue != -1)
{
//此句为了解决实际应用时数据刷新的问题
NumericValue = MaxValue - 1;
try
{
System.Threading.Thread.Sleep(0);
}
catch { }
NumericValue = MaxValue;
return;
}
NumericValue = vv;
}
else
{
//NumericValue = null;
}
}
}
}
/// <summary>
/// Lost焦点事件处理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void tbCntLostFocus(object sender, RoutedEventArgs e)
{
lock (lockObj)
{
TextBox tb = sender as TextBox;
bool isNumeric = IsNumber(tb.Text);
if (isNumeric && IsInteger)
{
isNumeric = IsWholeNumber(tb.Text);
}
decimal oldValue = this.AvaliableVal;
if (isNumeric)
{
decimal ctrlValue = Convert.ToDecimal(tb.Text);
if (ctrlValue < MinValue)
{
if (oldValue <= MaxValue && oldValue >= MinValue)
NumericValue = oldValue;
else
NumericValue = MinValue;
AvaliableVal = NumericValue;
}
else if (ctrlValue > MaxValue)
{
if (oldValue <= MaxValue && oldValue >= MinValue)
NumericValue = oldValue;
else
NumericValue = MaxValue;
AvaliableVal = NumericValue;
}
else
{
AvaliableVal = ctrlValue;
NumericValue = AvaliableVal;
}
}
else
{
if (oldValue > MaxValue || oldValue < MinValue)
oldValue = DefaultValue;
tb.Text = oldValue.ToString();
NumericValue = oldValue;
}
}
}
}
}
第3步、测试控件
MainWindow.xaml如下,无cs业务代码:
<Window x:Class="WpfUserControlApp11.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:uc="clr-namespace:WpfUserControlApp11"
Title="MainWindow" Height="300" Width="600">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<uc:MyNumUpDown
LabelVisibility="Visible"
IsInteger="True"
LabelWidth="70"
IsEnabled="true"
Width="250"
Height="50"
x:Name="mNum3"
NumericValue="108"
OffsetValue="1"
MinValue="1"
MaxValue="9999"
VerticalAlignment="Center"
LabeContent="产品价格:"
Margin="10"></uc:MyNumUpDown>
<uc:MyNumUpDown
LabelVisibility="Collapsed"
IsInteger="True"
LabelWidth="60"
IsEnabled="false"
Width="150"
Height="50"
x:Name="mNum4"
OffsetValue="1"
MinValue="0"
MaxValue="1000"
VerticalAlignment="Center"
LabeContent="值:"
Margin="50,10,10,10"></uc:MyNumUpDown>
</StackPanel>
</Grid>
</Window>
4、运行效果:
注:1)、以上代码添加到对应的VS工程代码中,即可正常运行出上述4的效果;
2)、转载请注明出处