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

3
我认为我已经阅读了谷歌搜索wpf mvvm-light数据验证时返回的每篇文章,但我不知道该怎么做。我知道Josh Smith、Karl Shifflett和MVVM LIGHT的数据验证演示技术。但大多数验证需要我在视图模型中完全“重新抽象化”我的模型。这意味着我必须为我想要验证的每个模型属性在我的视图模型中创建一个属性(在某些情况下将所有这些转换为字符串值以进行绑定/验证)。当我只想标记大多数字段为必填时,这似乎很冗余。
我正在使用LINQ到实体框架(带自跟踪)来获取来自SQL Server DB的模型类。因此,我更喜欢在我的视图模型中保留业务数据验证/规则。我编写了一个简单的服务接口来从模型中获取数据并将其传递给我的视图模型。
我能找到的大多数示例都可以追溯到2008年(例如Josh Smith)。这些技术是否仍然有效,或者是否有更多关于.NET 4.5等的最新MVVM数据验证最佳实践?
所以我想问:
1)您建议我使用哪些方法 2)在LINQ到EF和MVVM-Light环境中哪些方法最有效。 3)编辑:我想在用户输入数据时提供反馈,而不仅仅是在提交表单时。
谢谢。
2个回答

0
我最终使用了以下方法。我将我的模型更改为使用LINQ到自跟踪实体(有关STE信息,请参见此文章http://msdn.microsoft.com/en-us/library/vstudio/ff407090%28v=vs.100%29.aspx)。
LINQ到STE创建了一个OnPropertyChanged事件,实现了iNotifyPropertyChanged接口。
我只是为所需的匹配模型对象(linq实体生成代码)创建了一个公共部分类,并为OnPropertyChanged事件添加了事件处理程序。然后,我使用IDataErrorInfo接口进行验证并根据需要抛出错误。这使我能够在字段更改时验证它们,从而反映给用户。这还允许您执行可能需要重新查询数据库(例如查找用户名是否已被使用等)或抛出对话框的更高级别的验证逻辑。
此外,在模型中进行数据验证仍然允许我在执行直接“批量”操作(绕过UI)时进行验证。

我使用了HasErrorsHasChanges属性,并将它们用于创建一个布尔值,该值附加到继电器命令上,如果存在错误,则禁用crud命令按钮。

我将发布一些简单的代码来概述我刚才描述的内容,如果您需要更多细节,请评论。

这是模型类的Entity Framework扩展:

 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命令按钮。
这真是一场艰苦的战斗,才弄明白这些。

0

我处理这个问题的方式(不一定正确)是在ViewModel中进行验证(通常在CRUD操作中进行),然后如果有验证错误,就会中止保存/添加任何数据,并使用Messenger.Default.Send发送自定义消息类型到我的视图。然后我通过DialogBox或其他方式向用户发出警报。

我过去尝试过绑定ValidationRules,但发现最可靠和一致的方法是简单的if语句。


所以我假设您在表单中输入数据时不会向用户提供反馈,而是在调用crud命令对象时进行验证。 - J King
没错。如果你想提供实时反馈,我猜你需要一个绑定验证规则,但是我并没有在这方面取得太大成功。 - Echilon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接