我已经阅读了许多有关如何在WPF-MVVM中验证数据的文章,但是比起我开始更加困惑。
我想做的就是简单地向数据库添加新行。验证检查设备名称(要插入的对象)是否超过2个字符长和我想检查其唯一性,因此这会引起问题。
据我所知Model
应该注意自己的验证:例如字符长度,电子邮件地址有效性(如果具有电子邮件属性)等。但是,如何访问数据层以检查唯一性呢?根据我的理解,模型不应该知道有关该层的任何信息。现在,此验证规则已成为“业务”规则。
这是我的 RegisterViewModel
:
class RegisterViewModel : ViewModelBase, IDataErrorInfo
{
private string _DeviceName = "";
public string DeviceName
{
get { return _DeviceName; }
set
{
_DeviceName = value;
OnPropertyChanged("DeviceName");
}
}
public string Error
{
get
{
throw new NotImplementedException();
}
}
// We'd also check for uniqueness here?
public string this[string columnName]
{
get
{
string result = null;
if (columnName == "DeviceName" && String.IsNullOrEmpty(DeviceName))
{
return "Device name is required";
}
return result;
}
}
public RegisterViewModel()
{
DeviceName = System.Environment.MachineName;
}
public ICommand Register { get; set; }
}
当然,有些人会认为
IDataErrorInfo
应该在Model
类中实现,我会有些同意,但是同样,整个唯一性问题仍然存在。这是我的
device
模型:public partial class device
{
public int did { get; set; }
public int uid { get; set; }
public string Name { get; set; }
}
最后, View
<Window x:Class="IPdevices.Register"
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:IPdevices"
mc:Ignorable="d"
Title="Register" Height="202.884" Width="417.007" Icon="logo31_nowriting.ico" ResizeMode="NoResize" WindowStartupLocation="CenterScreen">
<Grid>
<GroupBox x:Name="groupBox" Header="Device" VerticalAlignment="Top" RenderTransformOrigin="0.877,2.187" Margin="10,10,10,0" Height="96">
<Grid Margin="0,0,3,3">
<Grid.RowDefinitions>
<RowDefinition Height="47*"/>
<RowDefinition Height="49*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="146*"/>
<ColumnDefinition Width="197*"/>
</Grid.ColumnDefinitions>
<TextBox x:Name="textBox" Height="24" TextWrapping="Wrap" VerticalAlignment="Top" Grid.Column="1" Margin="0,6,0,0" Text="{Binding Path=DeviceName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=true, NotifyOnValidationError=true}">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="Background" Value="Red"/>
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<Label x:Name="label" Content="Device Name:" RenderTransformOrigin="1.372,1.475" Margin="10,2,10,0" Height="28" VerticalAlignment="Top"/>
<TextBox x:Name="textBox1" Height="23" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Margin="0,7,0,0" Grid.Row="1" Grid.Column="1"/>
<Label x:Name="label1" Content="Location:" Margin="10,3,10,0" Grid.Row="1" Height="27" VerticalAlignment="Top"/>
</Grid>
</GroupBox>
<Button x:Name="button" Content="Register" Height="25" VerticalAlignment="Top" Margin="10,129,10,0" IsDefault="True" ToolTip="Register" Command="{Binding Register}"/>
</Grid>
</Window>
此时,验证成功,并且弹出红色轮廓。虽然我不确定如何处理设备名称的uniqueness属性。最重要的是,如何使“注册”按钮仅在一切都通过后才变为 Activity 状态?
任何输入将不胜感激。
最佳答案
公平的难题。当涉及数据验证时,您可以采用不同的方法,并且它们通常都可以正常工作。
因此,我将发表我的个人看法。阅读我写的有关MVVM的post可能有助于您理解我的立场。因此,让我们尝试回答您的每个问题:
是的,只要有可能,但是如您所见,您可能需要做更多的工作来进行一些验证
这是设计决定,但我通常会同意。
我真的不明白为什么?要特别小心“商务”一词。这种独特性是您的业务专家的真正要求吗?还是仅仅是技术规则,因为否则您就无法将其存储在关系数据库中?
无论如何,在我看来,当您需要某种东西来验证多个模型,或者需要某种东西来验证一个模型但使用外部数据(例如在您的示例中)时,它就被称为服务,它应该围绕用例构建(在我的案例中) post我以购买服务为例)
我认为IDataErrorInfo的设计是对世界的一种非常简单的看法。它可以在很少的CRUD应用程序中工作,但是在管理实际的业务应用程序时并不十分方便。我认为您不应该使用它。只需在 View 模型中添加属性,即可自行管理红色弹出窗口和内容。确实没有那么难,设置一个红色边框,在验证后更改您的属性,然后完成。
您的用例是什么?围绕此用例创建服务,并验证设备在该服务中的唯一性。
忘记IDataErrorInfo,自己实现即可。每当用户界面中的属性更新时,请再次调用您的验证服务。如果一切顺利,请激活您的按钮,否则请向用户指定错误的原因。
是否有意义?
关于c# - 错误处理WPF-MVVM,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39084276/