我想当我搜索wpf mvvm-light数据验证时,我已经阅读了谷歌返回的每一篇文章,我不知道该走哪条路。我知道josh smith, Karl Shifflett和MVVM LIGHT自己的数据验证演示技术。我看到的是,大多数验证要求我在视图模型中完全"重新抽象"模型。这意味着我必须在我的视图模型中为我想要验证的模型的每个属性创建一个属性(并且在某些情况下将所有这些转换为字符串值以进行绑定/验证)。当我想做的只是将大多数字段标记为必需时,这似乎是很多或冗余。
我使用LINQ实体框架(与自我跟踪)为我的模型类来自SQL服务器数据库。因此,我更愿意将业务数据验证/规则保留在视图模型中。我编写了一个简单的服务接口来从模型中获取数据并将其传递给我的视图模型。
我能找到的大多数例子都是从2008年开始的(比如josh smith)。这些技术是否仍然有效,或者在。net 4.5等中是否有更多最新的mvvm数据验证最佳实践?
所以我问:
你建议我用什么方法2)在MVVM-Light环境下LINQ to EF中,哪些方法最有效?3)编辑:我想提供反馈给用户,因为他们输入数据,而不仅仅是当他们提交表单谢谢
我这样做的方式(不一定正确)是在ViewModel (CRUD操作通常发生的地方)中进行验证,然后如果存在验证错误,则中止保存/添加任何数据并使用Messenger.Default.Send
向我的视图发送自定义消息类型。然后通过对话框或其他方式提醒用户。
我过去尝试过绑定ValidationRules,但发现到目前为止最可靠和一致的方法是简单的if
语句。
我最终使用了以下代码。我改变了我的模型,使用LINQ来自跟踪实体(有关STE http://msdn.microsoft.com/en-us/library/vstudio/ff407090%28v=vs.100%29.aspx的信息,请参阅本文)。
LINQ to STE创建一个OnPropertyChanged事件,实现iNotifyPropertyChanged接口。
我刚刚为匹配的模型对象(linq实体生成的代码)创建了一个公共部分类,并为OnPropertyChanged
事件添加了一个事件处理程序。然后,我使用IDataErrorInfo
接口来验证并根据需要抛出错误。这使我能够在字段发生变化时对其进行验证,并将其反映给用户。这也允许你执行更高级的验证逻辑,可能需要查询数据库(例如,查找用户名是否已被使用等)或抛出一个对话框
此外,在模型中进行数据验证允许我在执行绕过UI的直接"批处理"操作时仍然具有验证。
然后我使用HasErrors
和HasChanges
属性,并使用它们来创建一个布尔值,该值附加到中继命令,如果出现错误,则禁用crud命令按钮。
我将发布一些简单的代码来概述我刚刚描述的内容,如果你想了解更多细节,请评论。
下面是模型类的实体框架扩展:
Imports System.ComponentModel
Partial Public Class client
Implements IDataErrorInfo
#Region "Properties / Declarations"
'Collection / error description
Private m_validationErrors As New Dictionary(Of String, String)
Private _HasChanges As Boolean = False
''Marks object as dirty, requires saving
Public Property HasChanges() As Boolean
Get
Return _HasChanges
End Get
Set(value As Boolean)
If Not Equals(_HasChanges, value) Then
_HasChanges = value
OnPropertyChanged("HasChanges")
End If
End Set
End Property
'Extends the class with a property that determines
'if the instance has validation errors
Public ReadOnly Property HasErrors() As Boolean
Get
Return m_validationErrors.Count > 0
End Get
End Property
#End Region
#Region "Base Error Objects"
'Returns an error message
'In this case it is a general message, which is
'returned if the list contains elements of errors
Public ReadOnly Property [Error] As String Implements System.ComponentModel.IDataErrorInfo.Error
Get
If m_validationErrors.Count > 0 Then
Return "Client data is invalid"
Else
Return Nothing
End If
End Get
End Property
Default Public ReadOnly Property Item(ByVal columnName As String) As String Implements System.ComponentModel.IDataErrorInfo.Item
Get
If m_validationErrors.ContainsKey(columnName) Then
Return m_validationErrors(columnName).ToString
Else
Return Nothing
End If
End Get
End Property
#End Region
#Region "Base Error Methods"
'Adds an error to the collection, if not already present
'with the same key
Private Sub AddError(ByVal columnName As String, ByVal msg As String)
If Not m_validationErrors.ContainsKey(columnName) Then
m_validationErrors.Add(columnName, msg)
End If
End Sub
'Removes an error from the collection, if present
Private Sub RemoveError(ByVal columnName As String)
If m_validationErrors.ContainsKey(columnName) Then
m_validationErrors.Remove(columnName)
End If
End Sub
#End Region
Public Sub New()
Me.HasChanges = False
End Sub
#Region "Data Validation Methods"
''handles event and calls function that does the actual validation so that it can be called explicitly for batch processes
Private Sub ValidateProperty(ByVal sender As Object, ByVal e As PropertyChangedEventArgs) Handles Me.PropertyChanged
If e.PropertyName = "HasChanges" Then
Exit Sub
End If
IsPropertyValid(e.PropertyName)
HasChanges = True
End Sub
Public Function IsPropertyValid(sProperty As String) As Boolean
Select Case sProperty
''add validation by column name here
Case "chrLast"
If Me.chrLast.Length < 4 Then
Me.AddError("chrLast", "The last name is too short")
Return True
Else
Me.RemoveError("chrLast")
Return False
End If
Case Else
Return False
End Select
End Function
#End Region
End Class
,然后在视图模型中包含以下代码来绑定命令并评估它是否可以执行。
Public ReadOnly Property SaveCommand() As RelayCommand
Get
If _SaveCommand Is Nothing Then
_SaveCommand = New RelayCommand(AddressOf SaveExecute, AddressOf CanSaveExecute)
End If
Return _SaveCommand
End Get
End Property
Private Function CanSaveExecute() As Boolean
Try
If Selection.HasErrors = False And Selection.HasChanges = True Then
Return True
Else
Return False
End If
Catch ex As Exception
Return False
End Try
End Function
Private Sub SaveExecute()
''this is my LINQ to Self Tracking Entities DataContext
FTC_Context.SaveChanges()
End Sub
下面是我如何绑定我的按钮(在WPF中有自定义样式)
<Button Content="" Height="40" Style="{DynamicResource ButtonAdd}" Command="{Binding SaveCommand}" Width="40" Cursor="Hand" ToolTip="Save Changes" Margin="0,0,10,10"/>
因此,当没有验证错误并且当前客户端记录为"isDirty"时,保存按钮自动启用,如果这两个条件中的任何一个失败则禁用。这样,我现在就有了一种简单的方法来验证我想要用于实体的任何类型的列/数据,并且我可以在用户在表单中输入数据时提供反馈,并且只有在满足所有"条件"后才启用CRUD命令按钮。