我最近开始玩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那么请告诉我:)
答案 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>
截图:
顶部文本框具有焦点。我输入“-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.Text
为LostFocus
DependencyProperty
(if(int e = MyFunction())
{
MessageBox(e);
}
在声明类中注册int
时确定)。