项目中有些场景比如参数输入只能输入数字,要么自己定义输入键盘,要么自己定义TextBox样式
这里采用自定义Textbox,比较简陋
样式效果
1.继承TextBox这里是看了,在此基础上修改的WPF自定义数字输入框控件 - 五好青年,勇往直前 - 博客园 (cnblogs.com)
public string PMaxValue
{
get { return (string)GetValue(PMaxValueProperty); }
set { SetValue(PMaxValueProperty, value); }
}
// Using a DependencyProperty as the backing store for MaxValue. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PMaxValueProperty =
DependencyProperty.Register("PMaxValue", typeof(string), typeof(HsTextBox), new PropertyMetadata(""));
public string PMinValue
{
get { return (string)GetValue(PMinValueProperty); }
set { SetValue(PMinValueProperty, value); }
}
// Using a DependencyProperty as the backing store for MaxValue. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PMinValueProperty =
DependencyProperty.Register("PMinValue", typeof(string), typeof(HsTextBox), new PropertyMetadata(""));
public int PointLength
{
get { return (int)GetValue(PointLengthProperty); }
set { SetValue(PointLengthProperty, value); }
}
// Using a DependencyProperty as the backing store for PointLength. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PointLengthProperty =
DependencyProperty.Register("PointLength", typeof(int), typeof(HsTextBox), new PropertyMetadata(3));
public int NumberLength
{
get { return (int)GetValue(NumberLengthProperty); }
set { SetValue(NumberLengthProperty, value); }
}
// Using a DependencyProperty as the backing store for NumberLength. This enables animation, styling, binding, etc...
public static readonly DependencyProperty NumberLengthProperty =
DependencyProperty.Register("NumberLength", typeof(int), typeof(HsTextBox), new PropertyMetadata(7));
private string val = "";
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
string txt = this.Text;
int index = this.CaretIndex;
if (Text.Contains("."))
{
if (txt.Split('.')[1].Length >= PointLength && index > txt.Split('.')[0].Length && this.SelectionLength == 0)//控制小数点后输入位数
{
e.Handled = true;
return;
}
else if (txt.Split('.')[0].Length >= NumberLength && index <= txt.Split('.')[0].Length)//控制小数点前输入位数(有小数点)
{
e.Handled = true;
return;
}
}
else if (txt.Length == NumberLength && e.Key != Key.Decimal && e.Key != Key.OemPeriod)//控制小数点前输入位数(无小数点)
{
e.Handled = true;
return;
}
//如果是句号就是.
if (e.Key == Key.Decimal || e.Key == Key.OemPeriod)
{
val = ".";
}
else
{
val = "";
}
//屏蔽非法按键
if ((e.Key >= Key.NumPad0 && e.Key <= Key.NumPad9) || e.Key == Key.Decimal || e.Key == Key.Subtract || e.Key.ToString() == "Tab")
{
if (txt.Contains(".") && e.Key == Key.Decimal)
{
e.Handled = true;
return;
}
else if ((txt.Contains("-") || this.CaretIndex != 0) && e.Key == Key.Subtract)
{
e.Handled = true;
return;
}
e.Handled = false;
}
else if (((e.Key >= Key.D0 && e.Key <= Key.D9) || e.Key == Key.OemPeriod || e.Key == Key.OemMinus) && e.KeyboardDevice.Modifiers != ModifierKeys.Shift)
{
if (txt.Contains(".") && e.Key == Key.OemPeriod)
{
e.Handled = true;
return;
}
else if ((txt.Contains("-") || this.CaretIndex != 0) && e.Key == Key.OemMinus)
{
e.Handled = true;
return;
}
e.Handled = false;
}
else if (e.Key == Key.Back || e.Key == Key.Delete)
{
var inde = txt.LastIndexOf(txt);
txt.Remove(inde);
e.Handled = true;
}
else if (e.Key == Key.Enter)
{
Osklib.OnScreenKeyboard.Close();
}
else
{
e.Handled = true;
//this.Text = "";
if (e.Key.ToString() != "RightCtrl")
{ }
}
}
protected override void OnGotFocus(RoutedEventArgs e)
{
base.OnGotFocus(e);
this.Select(this.Text.Length, 0);
}
protected override void OnPreviewTextInput(TextCompositionEventArgs e)
{
string txt = this.Text;
string[] numberStr = new string[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "-", "." };
string strs = string.Empty;
for (int i = 0; i < txt.Length; i++)
{
if (numberStr.Contains(txt[i].ToString()))
{
strs += txt[i];
};
}
if (strs.StartsWith(".", StringComparison.Ordinal))
{
strs = txt.Insert(0, "0");
}
this.Text = strs;
this.Select(this.Text.Length, 0);
}
protected override void OnTextChanged(TextChangedEventArgs e)
{
string txt = this.Text;
int index = this.CaretIndex;
if (double.TryParse(txt, out double valu))
{
var v1 = double.TryParse(PMinValue, out double minv);
var v2 = double.TryParse(PMaxValue, out double mmaxv);
if (valu < minv)
{
var tmp1 = minv;
this.Text = tmp1.ToString();
e.Handled = true;
}
if (valu > mmaxv)
{
var tmp = mmaxv;
this.Text = tmp.ToString();
e.Handled = true;
}
}
this.Text = this.Text.Trim();
this.Select(this.Text.Length, 0);
}
}
2.样式定义,验证样式
<!--自定义数字框输入样式-->
<Style TargetType="{x:Type hsct:HsTextBox}" x:Key="ValidationHsTextBoxStyle">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="BorderBrush" Value="{StaticResource TextBox.Static.Border}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="Validation.ErrorTemplate" Value="{x:Null}"/>
<Setter Property="PMinValue" Value="{StaticResource ResourceKey=HsTextboxMinValue}"/>
<Setter Property="PMaxValue" Value="{StaticResource ResourceKey=HsTextboxMaxValue}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="True"
CornerRadius="5">
<Grid>
<Border Name="root" Background="Transparent"></Border>
<ScrollViewer x:Name="PART_ContentHost" Grid.Column="1" Focusable="false"
VerticalAlignment="Center" Margin="5,0"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"/>
<Popup StaysOpen="True" Name="Popp"
PlacementTarget="{Binding ElementName=root}" AllowsTransparency="True" Placement="Bottom"
VerticalOffset="0" HorizontalOffset="0" >
<TextBlock Text="{Binding Path=(Validation.Errors)[0].ErrorContent,RelativeSource={RelativeSource Mode=TemplatedParent}}" FontSize="14"
Foreground="Red" VerticalAlignment="Center"
HorizontalAlignment="Right" Margin="10,0" />
</Popup>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" TargetName="border" Value="0.56"/>
</Trigger>
<Trigger Property="AreAnyTouchesOver" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.Focus.Border}"/>
</Trigger>
<Trigger Property="IsReadOnly" Value="True">
<Setter TargetName="border" Property="Background" Value="#F7F9FA"/>
</Trigger>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="IsOpen" Value="true" TargetName="Popp"/>
</Trigger>
<Trigger Property="Validation.HasError" Value="False">
<Setter Property="IsOpen" Value="False" TargetName="Popp"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsInactiveSelectionHighlightEnabled" Value="true"/>
<Condition Property="IsSelectionActive" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="SelectionBrush" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
</MultiTrigger>
</Style.Triggers>
</Style>