WPF TextBox 仅允许输入数字
因为在 IValueConverter 实现中,当文本不能转换为目标类型时返回 DependencyProperty.UnsetValue ,Validation.GetHasError 返回 true ,为何要绕一个圈让用户输入不能转换的文本,然后再获取错误状态呢?不如直接不让用户输入错误文本,于是写了一个 Behavior 派生类:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Windows; 7 using System.Windows.Controls; 8 using System.Windows.Input; 9 using System.Windows.Interactivity; 10 11 namespace WpfApplication6 12 { 13 public class OnlyDigitalBehavior : Behavior<TextBox> 14 { 15 public Type DigitalType 16 { 17 get { return (Type)GetValue(DigitalTypeProperty); } 18 set { SetValue(DigitalTypeProperty, value); } 19 } 20 21 public static readonly DependencyProperty DigitalTypeProperty = 22 DependencyProperty.Register("DigitalType", typeof(Type), typeof(OnlyDigitalBehavior), new PropertyMetadata()); 23 24 25 protected override void OnAttached() 26 { 27 base.OnAttached(); 28 this.AssociatedObject.PreviewTextInput += AssociatedObject_PreviewTextInput; 29 DataObject.AddPastingHandler(this.AssociatedObject, AssociatedObject_Pasting); 30 InputMethod.SetIsInputMethodEnabled(this.AssociatedObject, false); 31 } 32 33 private void AssociatedObject_Pasting(object sender, DataObjectPastingEventArgs e) 34 { 35 e.CancelCommand(); 36 } 37 38 protected override void OnDetaching() 39 { 40 base.OnDetaching(); 41 this.AssociatedObject.PreviewTextInput -= AssociatedObject_PreviewTextInput; 42 DataObject.RemovePastingHandler(this.AssociatedObject, AssociatedObject_Pasting); 43 } 44 45 46 private void AssociatedObject_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e) 47 { 48 TextBox textBox = sender as TextBox; 49 Type digitalType = this.DigitalType; 50 if (textBox == null) 51 { 52 return; 53 } 54 if (digitalType == typeof(Int16)) 55 { 56 Int16 i = 0; 57 if (Int16.TryParse(textBox.Text + e.Text, out i)) 58 { 59 return; 60 } 61 } 62 else if (digitalType == typeof(Int32)) 63 { 64 Int32 i = 0; 65 if (Int32.TryParse(textBox.Text + e.Text, out i)) 66 { 67 return; 68 } 69 } 70 else if (digitalType == typeof(Int64)) 71 { 72 Int64 i = 0; 73 if (Int64.TryParse(textBox.Text + e.Text, out i)) 74 { 75 return; 76 } 77 } 78 else if (digitalType == typeof(double)) 79 { 80 double d = 0; 81 if (double.TryParse(textBox.Text + e.Text, out d)) 82 { 83 return; 84 } 85 } 86 else if (digitalType == typeof(decimal)) 87 { 88 decimal d = 0; 89 if (decimal.TryParse(textBox.Text + e.Text, out d)) 90 { 91 return; 92 } 93 } 94 e.Handled = true; 95 } 96 } 97 }
InputMethod.SetIsInputMethodEnabled(this.AssociatedObject, false); 作用是屏蔽输入法。
以下是测试View:
1 <Window x:Class="WpfApplication6.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 5 xmlns:local="clr-namespace:WpfApplication6" 6 xmlns:sys="clr-namespace:System;assembly=mscorlib" 7 Title="MainWindow" Height="350" Width="525"> 8 <StackPanel> 9 <TextBlock Margin="3">Int16</TextBlock> 10 <TextBox Margin="3"> 11 <i:Interaction.Behaviors> 12 <local:OnlyDigitalBehavior DigitalType="{x:Type sys:Int16}" /> 13 </i:Interaction.Behaviors> 14 </TextBox> 15 <TextBlock Margin="3">Int32</TextBlock> 16 <TextBox Margin="3"> 17 <i:Interaction.Behaviors> 18 <local:OnlyDigitalBehavior DigitalType="{x:Type sys:Int32}" /> 19 </i:Interaction.Behaviors> 20 </TextBox> 21 <TextBlock Margin="3">Int64</TextBlock> 22 <TextBox Margin="3"> 23 <i:Interaction.Behaviors> 24 <local:OnlyDigitalBehavior DigitalType="{x:Type sys:Int64}" /> 25 </i:Interaction.Behaviors> 26 </TextBox> 27 <TextBlock Margin="3">Double</TextBlock> 28 <TextBox Margin="3"> 29 <i:Interaction.Behaviors> 30 <local:OnlyDigitalBehavior DigitalType="{x:Type sys:Double}" /> 31 </i:Interaction.Behaviors> 32 </TextBox> 33 <TextBlock Margin="3">Decimal</TextBlock> 34 <TextBox Margin="3"> 35 <i:Interaction.Behaviors> 36 <local:OnlyDigitalBehavior DigitalType="{x:Type sys:Decimal}" /> 37 </i:Interaction.Behaviors> 38 </TextBox> 39 </StackPanel> 40 </Window>
如果大家有更好的实现方法欢迎赐教!
再来一个支持粘贴的:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Windows; 7 using System.Windows.Controls; 8 using System.Windows.Input; 9 using System.Windows.Interactivity; 10 11 namespace WpfApplication6 12 { 13 public class OnlyDigitalBehavior : Behavior<TextBox> 14 { 15 private string lastRight = null; 16 17 public Type DigitalType 18 { 19 get { return (Type)GetValue(DigitalTypeProperty); } 20 set { SetValue(DigitalTypeProperty, value); } 21 } 22 23 public static readonly DependencyProperty DigitalTypeProperty = 24 DependencyProperty.Register("DigitalType", typeof(Type), typeof(OnlyDigitalBehavior), new PropertyMetadata()); 25 26 27 protected override void OnAttached() 28 { 29 base.OnAttached(); 30 this.AssociatedObject.TextChanged += AssociatedObject_TextChanged; 31 InputMethod.SetIsInputMethodEnabled(this.AssociatedObject, false); 32 } 33 34 protected override void OnDetaching() 35 { 36 base.OnDetaching(); 37 this.AssociatedObject.TextChanged -= AssociatedObject_TextChanged; 38 } 39 40 private void AssociatedObject_TextChanged(object sender, TextChangedEventArgs e) 41 { 42 TextBox textBox = sender as TextBox; 43 Type digitalType = this.DigitalType; 44 if (textBox == null) 45 { 46 return; 47 } 48 if ((IsDigital(digitalType,textBox.Text) || string.IsNullOrEmpty(textBox.Text)) && lastRight != textBox.Text) 49 { 50 lastRight = textBox.Text; 51 } 52 else if (textBox.Text != lastRight) 53 { 54 textBox.Text = lastRight; 55 textBox.SelectionStart = textBox.Text.Length; 56 } 57 } 58 59 private bool IsDigital(Type targetType,string digitalString) 60 { 61 if (targetType == typeof(Int16)) 62 { 63 Int16 i = 0; 64 if (Int16.TryParse(digitalString, out i)) 65 { 66 return true; 67 } 68 } 69 else if (targetType == typeof(Int32)) 70 { 71 Int32 i = 0; 72 if (Int32.TryParse(digitalString, out i)) 73 { 74 return true; 75 } 76 } 77 else if (targetType == typeof(Int64)) 78 { 79 Int64 i = 0; 80 if (Int64.TryParse(digitalString, out i)) 81 { 82 return true; 83 } 84 } 85 else if (targetType == typeof(double)) 86 { 87 double d = 0; 88 if (double.TryParse(digitalString, out d)) 89 { 90 return true; 91 } 92 } 93 else if (targetType == typeof(decimal)) 94 { 95 decimal d = 0; 96 if (decimal.TryParse(digitalString, out d)) 97 { 98 return true; 99 } 100 } 101 return false; 102 } 103 } 104 }