无法绑定WPF中的浮点输入字段

时间:2016-04-23 13:02:40

标签: c# wpf xaml mvvm

我最近开始玩MVVM,在我遇到之前,我偶然发现了一个问题。

基本上我的模型中有一个double类型的属性,它链接到我的ViewModel中的字符串属性,实现了INotifyPropertyChanged接口,该接口绑定到文本框的Text属性,UpdateSourceTrigger被设置为PropertyChanged,但是文本框不允许我输入小数位或减号,也不能在没有应用程序崩溃的情况下将文本框设置为空白。

我彻底搜索了解决这个问题的方法,并找到了许多可能在某些方面起作用的解决方案,但却给我留下了其他问题。最后,我使用了一些组合来解决这个问题:

我发现this有用,并放置:

public App()
{
    System.Windows.FrameworkCompatibilityPreferences.KeepTextBoxDisplaySynchronizedWithTextProperty = false;
}
在App.xaml.cs中的

我现在可以在我的文本框中插入小数位。但我仍然无法使用' - ',也不能将文本框设置为空白。

为了解决这个问题,我做了两件事。在我的XAML中,我将以下StringFormat添加到我的数据绑定中。

<TextBox Text="{Binding StringLinkedToDouble, UpdateSourceTrigger=PropertyChanged, StringFormat=-N2}"/>

'N2'之前的' - '允许我输入一个减号,但除非我先输入数值然后在数字的开头输入' - ',否则代码会抛出错误。为了解决这个问题,以及我无法在不遇到错误的情况下将文本框设置为空白的事实,我在我的ViewModel中执行了此操作:

public StringLinkedToDouble
{
    get { return _model.DoubleToBeLinked.ToString(); }
    set
    {
        if ((value != "") && (value != "-"))
        _model.DoubleToBeLinked = Convert.ToDouble(value);
        RaisePropertyChanged("StringLinkedToDouble");
    }
}

虽然这可能有用,但我是MVVM的新手,我发布这个的原因是因为这个解决方案看起来非常简单,几乎太简单了,我担心MVVM可能不会“好”吗?我有一半期待被告知这不公平哈哈!如果是这种情况,那么有人会建议更好的选择吗?提前致谢! 如果还有其他我做过的不适当的MVVM那么请告诉我:)

1 个答案:

答案 0 :(得分:1)

我不会说你的解决方案“太简单”了。你已经自愿做了很多框架想要为你做的工作。

这就是我要做的事情:

查看模型

public class ViewModel : INotifyPropertyChanged
{
    private double _doubleValue = 0;
    public double DoubleValue
    {
        get { return _doubleValue; }
        set
        {
            _doubleValue = value;
            PropertyChanged?.Invoke(this, 
                new PropertyChangedEventArgs(nameof(DoubleValue)));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

XAML

<Window 
    x:Class="WPFTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WPFTest"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">

    <Window.DataContext>
        <local:ViewModel />
    </Window.DataContext>

    <Grid>
        <StackPanel Orientation="Vertical">
            <StackPanel Orientation="Horizontal" Margin="2">
                <Label>Double Value</Label>
                <TextBox 
                    Text="{Binding DoubleValue, UpdateSourceTrigger=PropertyChanged}" 
                    Width="300" />
            </StackPanel>
            <StackPanel Orientation="Horizontal" Margin="2">
                <Label>Double Value</Label>
                <TextBox Text="{Binding DoubleValue}" Width="300" />
            </StackPanel>
        </StackPanel>
    </Grid>
</Window>

截图:

Entering a broken double

顶部文本框具有焦点。我输入“-34”和“-34”出现在第二个文本框中,通过viewmodel绑定。然后我输入了垃圾,第一个TextBox无法将字符串转换为double,因此默认验证显示红色错误边框 - 并且viewmodel上的属性未更新,因此第二个文本框未更新。并且用户可以看到存在问题。

如果你这里唯一的目标只是让用户给你一个双倍的价值,那就是你需要的。

如果您想添加更多用户界面以帮助用户了解正在发生的事情,you can write a style or template trigger on Validation.HasError

我不是一个拒绝接受非数字键击的数字字段的忠实粉丝,因为它很难让它正常工作 - 正如你已经看到自己的减号经验。我不是很虔诚,但我更愿意向他们展示一个错误,让他们决定要输入哪些字符以及何时输入。

另外,从概念上讲,您的viewmodel不应该知道这种验证。对于视图模型而言,有必要担心双重超出范围,而不是用户正在键入的内容。 viewmodel应该有一个double属性,有人在那里设置它就是那样。检查最终用户键入的字符是视图的作业,而不是视图模型。将它留给TextBox(实际上,它可能是Binding正在做那项工作;由于某种原因,我从来没有困难找到它)将它保持在它所属的视图中。

您可能会尝试弄乱a custom value converter on the binding,但我认为没有任何方法可以做到这一切。但我更喜欢使用微软发布它的方式使用WPF双转换。我对他们发明那种轮子的方式感到满意。一个例外:尝试输入“-34e10”,当你到达'1'时它会尝试“帮助”。但是可以通过将UpdateSourceTrigger作为默认值来解决此问题,TextBox.TextLostFocus DependencyPropertyif(int e = MyFunction()) { MessageBox(e); } 在声明类中注册int时确定)。