我想当我搜索wpf mvvm-light数据验证时,我已阅读google返回的每篇文章,我不知道要走哪条路。我知道josh smith,Karl Shifflett和MVVM LIGHT自己的数据验证演示技术。我看到的是,大多数验证都要求我在视图模型中完全“重新抽象”我的模型。这意味着我必须在我的viewmodel中为我想验证的模型的每个属性创建一个属性(在某些情况下,将所有这些属性转换为字符串值以进行绑定/验证)。当我想要做的就是根据需要标记大多数字段时,这似乎很多或冗余。
我正在为来自SQL Server DB的模型类使用LINQ to实体框架(具有自我跟踪)。因此,我更愿意在我的视图模型中保留业务数据验证/规则。我编写了一个简单的服务接口来从模型中获取数据并将其传递给我的viewmodel。
我能找到的大部分例子都是早在2008年(即乔什史密斯)。这些技术是否仍然有效,或者是否有更新的使用.NET 4.5等进行mvvm数据验证的最新实践。
所以我在问:
1)您建议我使用哪种方法 2)哪些方法在具有MVVM-Light环境的LINQ到EF中最有效。 3)编辑:我想在用户输入数据时向用户提供反馈,而不仅仅是在他们提交表单时
感谢
答案 0 :(得分:0)
我这样做(不一定正确)的方法是在ViewModel(通常进行CRUD操作)中进行验证,然后如果存在验证错误,则中止保存/添加任何数据并使用{{1} }将自定义消息类型发送到我的视图。然后我通过DialogBox或其他方式提醒用户。
我过去曾尝试使用Binding ValidationRules,但迄今为止发现最简单Messenger.Default.Send
语句的最可靠和一致的方法。
答案 1 :(得分:0)
我最终使用了以下内容。我改变了我的模型以使用LINQ来自我跟踪实体(有关STE http://msdn.microsoft.com/en-us/library/vstudio/ff407090%28v=vs.100%29.aspx的信息,请参阅此文章)。
LINQ to STE创建一个实现iNotifyPropertyChanged接口的OnPropertyChanged事件。
我刚为匹配的模型对象(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命令按钮满足。
这是一场很难找到的战斗。