我怎样才能格式化势必文本框小数没有激怒我的用户?(How can I format a decima

2019-06-26 06:54发布

我试图使用显示在数据绑定WPF在TextBox格式化小数。

目标

目标1:在码设置一个十进制属性,在TextBox显示器2位小数。

目标2:当用户与文本框(在类型)相互作用,不要激怒他/她。

目标3:绑定必须的PropertyChanged更新源。

尝试

尝试1:无格式。

在这里,我们将从头开始接近。

<TextBox Text="{Binding Path=SomeDecimal, UpdateSourceTrigger=PropertyChanged}" />

违反目标1. SomeDecimal = 4.5会显示“4.50000”在文本框中。

尝试2:使用的StringFormat的约束力。

<TextBox Text="{Binding Path=SomeDecimal, UpdateSourceTrigger=PropertyChanged, StringFormat=F2}" />

违反目标2.说SomeDecimal是2.5,和文本框被显示“2.50”。 如果我们选择所有,输入“13.5”我们在TextBox结束了“00年5月13日”,因为格式化“有益”插入小数和零。

尝试3:使用扩展WPF工具包的MaskedTextBox中。

http://wpftoolkit.codeplex.com/wikipage?title=MaskedTextBox

假设我在正确的阅读文档,面膜## 0.00手段“两个可选的数字,后面所需的数字,一个小数点和两个需要的数字。这迫使我说”尽可能多的能够进入这个文本框是999.99" ,但让我们说,我很确定这一点。

<xctk:MaskedTextBox Value="{Binding Path=SomeDecimal, UpdateSourceTrigger=PropertyChanged}" Mask="##0.00" />

违反目标2.文本框开头___.__和选择它并键入5.75产生575.__ 。 获得5.75的唯一途径是选择文本框和键入<space><space>5.75

尝试4:使用扩展WPF工具包的DecimalUpDown微调。

http://wpftoolkit.codeplex.com/wikipage?title=DecimalUpDown

<xctk:DecimalUpDown Value="{Binding Path=SomeDecimal, UpdateSourceTrigger=PropertyChanged}" FormatString="F2" />

违反目标3. DecimalUpDown愉快地忽略UpdateSourceTrigger =的PropertyChanged。 一个扩展的WPF工具包Codeplex上页面上的协调员建议在修改的ControlTemplate http://wpftoolkit.codeplex.com/discussions/352551/ 。 这满足目标3,但违反目标2,表现出相同的行为在尝试2。

尝试5:使用样式datatriggers,仅使用,如果用户不编辑格式。

绑定到双用的StringFormat上一个TextBox

即使这样一个满足所有三个进球,我不希望使用它。 (A)文本框成为每个代替1- 12行,以及我的应用程序包含许多,许多文本框。 (B)我所有的文本框已经有一个指向一个全球性的StaticResource它设置保证金,身高,和其他的东西样式属性。 (C)你可能已经注意到下面的代码设置绑定路径两次,这违反了DRY原则。

<TextBox>
    <TextBox.Style>
        <Style TargetType="{x:Type TextBox}">
            <Setter Property="Text" Value="{Binding Path=SomeDecimal, StringFormat=F2}" />
            <Style.Triggers>
                <Trigger Property="IsFocused" Value="True">
                    <Setter Property="Text" Value="{Binding Path=SomeDecimal, UpdateSourceTrigger=PropertyChanged}" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </TextBox.Style>
</TextBox>

所有这些不舒服的事情放在一边......

违反目标2.首先,点击其显示“13.50”突然使得它显示“13.5000”文本框,这是出乎意料的。 其次,如果从空白文本框,然后我输入“13.50”,文本框将包含“1350”。 我无法解释为什么,但按句号键如果光标在文本框字符串的右端不插入小数。 如果文本框包含长度> 0的字符串,并且我重新定位光标到任意位置,除了字符串的右端,然后我可以插入小数点。

尝试6:做我自己。

我即将踏上痛苦的jouney,方法是子类文本框,或创​​建一个附加属性,并编写格式代码自己。 这将是充满字符串操作,并造成大量脱发。


有没有人有格式化必将满足所有上述目标的文本框小数有什么建议?

Answer 1:

尝试解决在视图模型的水平。 它:

public class FormattedDecimalViewModel : INotifyPropertyChanged
    {
        private readonly string _format;

        public FormattedDecimalViewModel()
            : this("F2")
        {

        }

        public FormattedDecimalViewModel(string format)
        {
            _format = format;
        }

        private string _someDecimalAsString;
        // String value that will be displayed on the view.
        // Bind this property to your control
        public string SomeDecimalAsString
        {
            get
            {
                return _someDecimalAsString;
            }
            set
            {
                _someDecimalAsString = value;
                RaisePropertyChanged("SomeDecimalAsString");
                RaisePropertyChanged("SomeDecimal");
            }
        }

        // Converts user input to decimal or initializes view model
        public decimal SomeDecimal
        {
            get
            {
                return decimal.Parse(_someDecimalAsString);
            }
            set
            {
                SomeDecimalAsString = value.ToString(_format);
            }
        }

        // Applies format forcibly
        public void ApplyFormat()
        {
            SomeDecimalAsString = SomeDecimal.ToString(_format);
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

样品

XAML:

<TextBox x:Name="tb" Text="{Binding Path=SomeDecimalAsString, UpdateSourceTrigger=PropertyChanged}" />

后面的代码:

public MainWindow()
{
    InitializeComponent();
    FormattedDecimalViewModel formattedDecimalViewModel = new FormattedDecimalViewModel { SomeDecimal = (decimal)2.50 };
    tb.LostFocus += (s, e) => formattedDecimalViewModel.ApplyFormat(); // when user finishes to type, will apply formatting
    DataContext = formattedDecimalViewModel;
}


Answer 2:

我创建了下面的自定义行为来移动用户在使用时光标到小数点后StringFormat={}{0:0.00}这迫使一个小数位是存在,但是这可能会导致以下问题:

违反目标2.说SomeDecimal是2.5,和文本框被显示“2.50”。 如果我们选择所有,输入“13.5”我们在TextBox结束了“00年5月13日”,因为格式化“有益”插入小数和零。

我一直在使用,将当他们按小数点后的用户将光标移动到一个自定义的行为,解决这个砍死。 键:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;

namespace GUI.Helpers.Behaviors
{
    public class DecimalPlaceHotkeyBehavior : Behavior<TextBox>
    {
        #region Methods
        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.PreviewKeyDown += AssociatedObject_PreviewKeyDown;
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.PreviewKeyDown -= AssociatedObject_PreviewKeyDown;
        }

        protected override Freezable CreateInstanceCore()
        {
            return new DecimalPlaceHotkeyBehavior();
        }
        #endregion

        #region Event Methods
        private void AssociatedObject_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (e.Key == System.Windows.Input.Key.OemPeriod || e.Key == System.Windows.Input.Key.Decimal)
            {
                var periodIndex = AssociatedObject.Text.IndexOf('.');
                if (periodIndex != -1)
                {
                    AssociatedObject.CaretIndex = (periodIndex + 1);
                    e.Handled = true;
                }
            }
        }
        #endregion

        #region Initialization
        public DecimalPlaceHotkeyBehavior()
            : base()
        {
        }
        #endregion
    }
}

我使用它,如下所示:

<TextBox xmlns:Behaviors="clr-namespace:GUI.Helpers.Behaviors" 
         xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
         Text="{Binding Value, UpdateSourceTrigger=PropertyChanged, StringFormat={}{0:0.00}}">
        <i:Interaction.Behaviors>
            <Behaviors:DecimalPlaceHotkeyBehavior></Behaviors:DecimalPlaceHotkeyBehavior>
        </i:Interaction.Behaviors>
</TextBox>


Answer 3:

尝试扩展的无线工具包屏蔽文本框的WPF来实现输入掩码: http://wpftoolkit.codeplex.com/wikipage?title=MaskedTextBox

例:

<toolkit:MaskedTextBox Mask="(000) 000-0000" Value="(555) 123-4567" 
IncludeLiterals="True" />


文章来源: How can I format a decimal bound to TextBox without angering my users?