在输入错误时将文本框绑定到十进制“后备值”

时间:2017-03-19 01:21:40

标签: c# wpf data-binding

我今天在WPF中测试数据绑定的细微差别,我遇到了一个奇怪的问题。

在我看来,我有

<TextBox Text="{Binding MyInt, UpdateSourceTrigger=LostFocus, StringFormat='{}{##.##}'}"/>        
<Label Content="{Binding MyStr2}"/>

在我的ViewModel中,我有

    private decimal myInt;

    public decimal MyInt
    {
        get { return myInt; }
        set
        {
            if (value == myInt) { return; }
            myInt = value;               
            OnPropertyChange();
            OnPropertyChange("MyStr2");
        }
    }

    public string MyStr2
    {
        get
        {
            return myInt.ToString("N2", CultureInfo.CreateSpecificCulture("en-IN"));
        }

    }

我想从文本框中获取数据,并将其正确格式化并将其显示在标签中。简单易行。

现在,我只能在文本框中输入十进制数据,否则边框会变为红色,表示输入错误。

输入十进制数据时,一切正常:Working fine

但是,当我输入垃圾数据时,会发生这种情况:Error

红色边框显示数据输入错误。但是,该标签仍然反映了较旧的数据。如果输入错误,我希望标签回落到0.00。有没有办法做到这一点?

我试图找到一种人为的方法来做到这一点,并且它以一种极其笨拙的方式运作。

    private string myInt;
    private decimal myIntActual;

    public string MyInt
    {
        get
        {
            return myInt;
        }
        set
        {
            if (value == myInt) { return; }
            Decimal.TryParse(value.ToString(), out myIntActual);
            myInt = myIntActual.ToString();
            Decimal.TryParse(myInt, out myIntActual);
            OnPropertyChange();
            OnPropertyChange("MyStr2");
        }
    }

    public string MyStr2
    {
        get
        {
            return myIntActual.ToString("N2", CultureInfo.CreateSpecificCulture("en-IN"));
        }
    }

这样做是,它将输入作为字符串,尝试将其解析为十进制,如果它不能,它将返回零。但是我已经牺牲了这段代码的输入验证,更不用说代码看起来很难看。

据我所知,绑定失败时WPF具有回退值机制。输入错误时是否有任何回退值机制?

编辑:

还有一件事。输入垃圾数据后,下次输入有效数据时,该值会以某种方式到达视图模型,但文本框变为空白。这是一个可以重现的问题。

截图A:

Working correctly

这是按预期工作的。

Garbage data

然后输入垃圾数据。请注意,由于UpdateSourceTriggerLostFocus,因此在焦点丢失之前不会出现错误。

Valid data

然后我输入有效数据,然后......

Gone!

失去焦点后,文本框会消失。请注意,标签已正确更新。我设置断点以查看绑定属性是否更新,但是文本框变为空白。那是为什么?

1 个答案:

答案 0 :(得分:1)

这是触发器的想法。我测试了这个,它对我有用。它不会对您的viewmodel或后面的代码进行任何更改。

<TextBox 
    x:Name="MyIntTextBox"
    Text="{Binding MyInt, UpdateSourceTrigger=LostFocus, StringFormat='{}{##.##}'}"
    />
<Label Content="{Binding MyStr2}">
    <Label.Style>
        <Style TargetType="Label" BasedOn="{StaticResource {x:Type Label}}">
            <Style.Triggers>
                <!-- 
                parens on (Validation.HasError) are important: It's an attached 
                so its name has a dot in it. The parens tell the binding that.
                --> 
                <DataTrigger 
                    Binding="{Binding (Validation.HasError), ElementName=MyIntTextBox}" 
                    Value="True">
                    <Setter 
                        Property="Visibility" 
                        Value="Hidden" 
                        />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Label.Style>
</Label>

对于消隐行为,我看到当我在MyInt框中键入无效字符串时,选项卡输出,重新标签,键入有效值,然后选项卡退出。只有在我选中有效值时,才会发生这种情况,此时我选中的上一个值无效。我认为这正是你所描述的(错误)行为。

我没有解释。我不喜欢在框架上大肆宣传“bug”,但我认为这是一个错误。该控件未显示其绑定的viewmodel属性值,并且该值未更改。我在MyInt setter中放了一个断点,它只用一个新的有效值击中断点一次(除了据我所知,没有显示为空字符串的整数值)。

如果谷歌没有提出任何解决方法,我会问这个问题。我试过“wpf textbox invalid tab out empty”并没有得到任何结果。