错误处理WPF - MVVM
本文关键字:MVVM WPF 处理 错误 | 更新日期: 2023-09-27 18:03:23
我已经阅读了许多关于如何在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>
在这一点上,验证工作,并弹出一个红色的轮廓。虽然我不确定如何处理设备名称的唯一性属性。最重要的是,我如何允许注册按钮成为活动只有当一切通过?
公平地说,这是个很难回答的问题。当涉及到数据验证时,你可以有不同的方法,它们通常都是有效的。
因此,我将给出我个人的观点。阅读这篇我写的关于MVVM的文章可能会帮助你理解我的立场。所以让我们试着回答你的每一个问题:
模型,从我的理解应该照顾自己验证
是的,只要是可能的,但是正如你所看到的,你可能需要做更多的验证
模型不应该知道任何关于该层的信息。
这是一个设计决定,但我基本上同意。
这个验证规则,现在已经成为一个"业务"规则。
我真的不明白为什么?一定要小心使用"business"这个词。这种独特性是你的业务专家的真正要求吗?或者这仅仅是一个技术规则,因为您不能将其存储在关系数据库中?
无论如何,在我看来,当你需要一些东西来验证几个模型,或者一些东西来验证一个模型,但使用外部数据(如在你的例子)被称为服务,它应该围绕用例构建(在我的帖子中,我以购买服务为例)
当然,有些人会认为应该实现IDataErrorInfo在Model类 中
我认为IDataErrorInfo是用一种非常简单的世界观来设计的。它适用于小型CRUD应用程序,但对于管理实际的业务应用程序并不真正方便。我认为你不应该使用它。只要在视图模型中添加属性,自己管理红色弹出框之类的。这并不难,添加一个红色边框,在验证后更改属性,就完成了。
虽然我不确定如何处理唯一性属性的设备名称。
你的用例是什么?围绕这个用例创建一个服务,并在这个服务中验证你的设备的唯一性。
最重要的是,我如何允许注册按钮成为活动的当一切都过去了?
忘掉IDataErrorInfo,自己实现它。当UI中的属性更新时,再次调用验证服务。如果一切顺利,激活你的按钮,否则向用户说明为什么它不正确。
有意义吗?