问题描述
是否有任何体面的方法来获取绑定到 decimal 值的 WPF 控件?
当我只是将 TextBox 或 DataGridTextColumn 绑定到 decimal 时,数据输入是个问题.
<TextBox Text="{Binding MyDecimal, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"/>
当我尝试在这个 TextBox 中输入"0,5"时,我会得到"5".几乎不可能输入"0,5"(除了输入 1,5 并将"1"替换为"0").
当我使用 StringFormat 时,数据输入只是略微改进:
<TextBox Text="{Binding MyDecimal, StringFormat=F1, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"/>
现在,当我尝试输入"0,5"时,我最终会得到"0,5,0",这仍然是错误的,但至少我可以毫不费力地删除尾随的",0".
不过,使用 WPF 输入 decimal 类型还是很尴尬的,因为这些 TextBox 非常容易出现数据输入错误,尤其是对于值而言,这是一个真正的痛苦!
那么我应该在 WPF 中使用什么来输入十进制数据?还是微软不支持十进制数据??
推荐答案
我目前将此行为用于数字和十进制输入:
public class TextBoxInputBehavior : Behavior<TextBox> { const NumberStyles validNumberStyles = NumberStyles.AllowDecimalPoint | NumberStyles.AllowThousands | NumberStyles.AllowLeadingSign; public TextBoxInputBehavior() { this.InputMode = TextBoxInputMode.None; this.JustPositivDecimalInput = false; } public TextBoxInputMode InputMode { get; set; } public static readonly DependencyProperty JustPositivDecimalInputProperty = DependencyProperty.Register("JustPositivDecimalInput", typeof(bool), typeof(TextBoxInputBehavior), new FrameworkPropertyMetadata(false)); public bool JustPositivDecimalInput { get { return (bool)GetValue(JustPositivDecimalInputProperty); } set { SetValue(JustPositivDecimalInputProperty, value); } } protected override void OnAttached() { base.OnAttached(); AssociatedObject.PreviewTextInput += AssociatedObjectPreviewTextInput; AssociatedObject.PreviewKeyDown += AssociatedObjectPreviewKeyDown; DataObject.AddPastingHandler(AssociatedObject, Pasting); } protected override void OnDetaching() { base.OnDetaching(); AssociatedObject.PreviewTextInput -= AssociatedObjectPreviewTextInput; AssociatedObject.PreviewKeyDown -= AssociatedObjectPreviewKeyDown; DataObject.RemovePastingHandler(AssociatedObject, Pasting); } private void Pasting(object sender, DataObjectPastingEventArgs e) { if (e.DataObject.GetDataPresent(typeof(string))) { var pastedText = (string)e.DataObject.GetData(typeof(string)); if (!this.IsValidInput(this.GetText(pastedText))) { System.Media.SystemSounds.Beep.Play(); e.CancelCommand(); } } else { System.Media.SystemSounds.Beep.Play(); e.CancelCommand(); } } private void AssociatedObjectPreviewKeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.Space) { if (!this.IsValidInput(this.GetText(" "))) { System.Media.SystemSounds.Beep.Play(); e.Handled = true; } } } private void AssociatedObjectPreviewTextInput(object sender, TextCompositionEventArgs e) { if (!this.IsValidInput(this.GetText(e.Text))) { System.Media.SystemSounds.Beep.Play(); e.Handled = true; } } private string GetText(string input) { var txt = this.AssociatedObject; int selectionStart = txt.SelectionStart; if (txt.Text.Length < selectionStart) selectionStart = txt.Text.Length; int selectionLength = txt.SelectionLength; if (txt.Text.Length < selectionStart + selectionLength) selectionLength = txt.Text.Length - selectionStart; var realtext = txt.Text.Remove(selectionStart, selectionLength); int caretIndex = txt.CaretIndex; if (realtext.Length < caretIndex) caretIndex = realtext.Length; var newtext = realtext.Insert(caretIndex, input); return newtext; } private bool IsValidInput(string input) { switch (InputMode) { case TextBoxInputMode.None: return true; case TextBoxInputMode.DigitInput: return CheckIsDigit(input); case TextBoxInputMode.DecimalInput: decimal d; //wen mehr als ein Komma if (input.ToCharArray().Where(x => x == ',').Count() > 1) return false; if (input.Contains("-")) { if (this.JustPositivDecimalInput) return false; if (input.IndexOf("-",StringComparison.Ordinal) > 0) return false; if(input.ToCharArray().Count(x=>x=='-') > 1) return false; //minus einmal am anfang zulässig if (input.Length == 1) return true; } var result = decimal.TryParse(input, validNumberStyles, CultureInfo.CurrentCulture, out d); return result; default: throw new ArgumentException("Unknown TextBoxInputMode"); } return true; } private bool CheckIsDigit(string wert) { return wert.ToCharArray().All(Char.IsDigit); } } public enum TextBoxInputMode { None, DecimalInput, DigitInput }
XAML 用法如下所示:
<TextBox Text="{Binding Sum}"> <i:Interaction.Behaviors> <Behaviors:TextBoxInputBehavior InputMode="DecimalInput"/> </i:Interaction.Behaviors> </TextBox>
相关问答
相关标签/搜索