使用MVVM-Light WPF和Linq to Entity框架进行数据验证



我想当我搜索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的直接"批处理"操作时仍然具有验证。

然后我使用HasErrorsHasChanges属性,并使用它们来创建一个布尔值,该值附加到中继命令,如果出现错误,则禁用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命令按钮。

最新更新