Data validation with MVVM-Light WPF and Linq to Entity Framework

I think I have read every google article as I go through wpf mvvm-light and I have no idea where to go. I know that Josh smith, Karl Shifflett's and MVVM LIGHT use their own demo methods to validate the data. I see that more validation requires me to completely "rethink" my model in my view model. This means I need to create a property in my view model for every property on my model that I want to check (and in some cases convert the whole thing to string values ​​for binding / validation). This seems like a lot or redundancy where all I want to do is mark most of the fields as needed.

I am using LINQ for entity structure (self-checking) for my model classes which come from a SQL server database. As a result, I would rather keep the validation / rules of my business data in my view models. I am writing a simple service interface to get data from a model and pass it to my view model.

Most of the examples I can find date back to 2008 (like josh smith). Are these methods valid or are there more modern guidelines for validating mvvm data with .NET 4.5, etc.

So I ask:

1) What methods do you suggest using 2) What methods work best in LINQ to EF with MVVM-Light framework. 3) EDIT: I want to provide feedback to the user when they enter data, not just when the form is submitted

thank

+3


source to share


2 answers


I ended up using the following. I changed my model to use LINQ for self-tracking entities (see this article for information on STE http://msdn.microsoft.com/en-us/library/vstudio/ff407090%28v=vs.100%29. aspx ).

LINQ to STE raises the OnPropertyChanged event, which implements the iNotifyPropertyChanged interface.

I just created a public partial class for the corresponding model object (entity generated linq code) that I wanted and added an event handler for the event OnPropertyChanged

. Then I used the interface IDataErrorInfo

to check and IDataErrorInfo

error as needed. This allows me to validate fields as they change, which is reflected in the user. It also allows you to perform more advanced validation logic that might be required to query the database (i.e. to find if the username is already in use, etc.) or to create a dialog box.

In addition, having data validation in the model allows me to still have validation if I do direct "batch" operations that bypass the UI.

I then used HasErrors

and HasChanges

and used them to create a boolean that is attached to the relay commands, disabling the crud command buttons when there are errors.

I will post some simple code to describe what I just described, please comment if you want more details.

Here is an extension of the Entity Framework model class:



 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

      

I then included the following code in the view model to bind the command and evaluate if it could be executed.

 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

      

below shows how i bound my button (has its own style in WPF)

 <Button Content="" Height="40" Style="{DynamicResource ButtonAdd}" Command="{Binding SaveCommand}" Width="40" Cursor="Hand" ToolTip="Save Changes" Margin="0,0,10,10"/>

      

thus, when there are no validation errors and the current client record is "isDirty", the save button is automatically enabled and disabled if either of these two conditions are not met. So I now have an easy way to validate whatever column / data type I want for an entity, and I can provide feedback to the user when they enter data into the form, and only enable CRUD command buttons after all my "conditions" were met met.

It was a real battle to understand.

0


source


The way I do this (not necessarily correct) is to do my validation in the ViewModel (where CRUD operations usually do), and then if there are validation errors, abort saving / appending any data and use Messenger.Default.Send

to send a custom post type to mine representation. Then I alert the user via DialogBox or otherwise.



I've experimented with Binding ValidationRules in the past, but by far the simplest statement has become the most reliable and consistent method if

.

0


source







All Articles