Showing posts with label WPF. Show all posts
Showing posts with label WPF. Show all posts

Friday, January 4, 2013

Validate all controls in XAML

Ever thought how to validate all controls in WPF when a user submits a form?

With WPF, you have access to the visual tree and with this in hand, I created my little validator called 'BadAssValidation' :) which enumerates down the tree to find controls to validate.

What I do is that on the submit button in my application, I use the 'Command Parameter' and I pass in the Grid where all the controls that I want to validate exists.
 
<Button Height="23" HorizontalAlignment="Right" Margin="0,0,6,26" Name="btSave" VerticalAlignment="Bottom" Width="75" 
Command="{Binding Path=SaveOrderCommand}" CommandParameter="{Binding ElementName=OrderGrid}" Content="Save" />

Note that each individual control needs to have been bound to their own validator in order for the BadAssValidation to check if they have erroros.

<Binding.ValidationRules>
<validate:valMXvarchar300/>
</Binding.ValidationRules>

In the View Model, I now run the BadAssValidation on the Grid. The validator will enumerate through the visual tree to find matching controls. It will then check if any of these controls have failed validation.

'Validate with BadAssValidationDim validationObj As New Validator.BadAssValidation
If Not validationObj.enumVisual(param) Then
...


And here is the BadAssValidator class:

  Public Class BadAssValidation
  
     Private hasErrors As Boolean = False
  
     ''' <summary>
  
     ''' <para>Validation for all textboxes and comboboxes on UserControl.
  
     ''' </para>
  
     ''' <para>This method loops through textboxes and comboboxes on usercontrol
  
     ''' and calls their Binding validation rule if one exists.</para>
  
     ''' </summary>
  
     ''' <param name="visual">Visual</param>
  
     ''' <returns>Boolean: True if all controls pass validation : else false.</returns>
  
     ''' <remarks></remarks>
  
     Public Function enumVisual(ByVal visual As Visual) As Boolean
  
       Try
  
         ''Count children in visual tree node
  
         Dim j As Integer = VisualTreeHelper.GetChildrenCount(visual) - 1
  
         ''Loop through visual child
  
         For i As Integer = 0 To j
  
           Dim childvisual As Visual = CType(VisualTreeHelper.GetChild(visual, i), Visual)
  
           ''Check if child has a name
  
           If Not childvisual.DependencyObjectType.Name Is Nothing OrElse Not childvisual.DependencyObjectType.Name = "" Then
  
             ''Check if child is of 'TextBox'
  
             If childvisual.DependencyObjectType.Name = "TextBox" Then
  
               Dim txtbox As TextBox = childvisual
  
               ''Update source of control
  
               If Not txtbox.GetBindingExpression(TextBox.TextProperty) Is Nothing Then txtbox.GetBindingExpression(TextBox.TextProperty).UpdateSource()
  
               ''Check if control has errors
  
               If System.Windows.Controls.Validation.GetHasError(txtbox) Then hasErrors = True
  
               'for testing, need to create a new object before use   ': st.Append(txtbox.Name & vbNewLine) : MessageBox.Show(st.ToString)
  
             End If
  
             ''Check if child is of 'ComboBox'
  
             If childvisual.DependencyObjectType.Name = "ComboBox" Then
  
               Dim combox As ComboBox = childvisual
  
               ''Update source of control --Tag
  
               If Not combox.GetBindingExpression(ComboBox.TagProperty) Is Nothing Then combox.GetBindingExpression(ComboBox.TagProperty).UpdateSource()
  
               ''Update source of control --SelectedValue
  
               If Not combox.GetBindingExpression(ComboBox.SelectedValueProperty) Is Nothing Then combox.GetBindingExpression(ComboBox.SelectedValueProperty).UpdateSource()
  
               ''Check if control has errors
  
               If System.Windows.Controls.Validation.GetHasError(combox) Then hasErrors = True
  
               'for testing, need to create a new object before use   ': st.Append(combox.Name & vbNewLine) : MessageBox.Show(st.ToString)
  
             End If
  
             ''Check if child is of 'DatePicker'
  
             If childvisual.DependencyObjectType.Name = "DatePicker" Then
  
               Dim dPicker As DatePicker = childvisual
  
               ''Update source of control
  
               If Not dPicker.GetBindingExpression(DatePicker.SelectedDateProperty) Is Nothing Then dPicker.GetBindingExpression(DatePicker.SelectedDateProperty).UpdateSource()
  
               ''Check if control has errors
  
               If System.Windows.Controls.Validation.GetHasError(dPicker) Then hasErrors = True
  
               'for testing, need to create a new object before use   ': st.Append(txtbox.Name & vbNewLine) : MessageBox.Show(st.ToString)
  
             End If
  
           End If
  
           enumVisual(childvisual)
  
         Next i
  
       Catch ex As Exception
  
         Dim resultObj As New Results
  
         resultObj.displayResult(ex)
  
       End Try
  
       Return hasErrors
  
     End Function
  
     'Private st As System.Text.StringBuilder
  
   End Class
  
   Public Class val0ApprovedRegions
  
     Inherits ValidationRule
  
     Public Overrides Function Validate(ByVal value As Object, ByVal cultureInfo As System.Globalization.CultureInfo) As System.Windows.Controls.ValidationResult
  
       Dim valChar As Char = CChar(value)
  
       If valChar = "T" Then
  
         Return New ValidationResult(False, "Approved regions must be selected.")
  
       Else
  
         Return New ValidationResult(True, Nothing)
  
       End If
  
     End Function
  
   End Class  

RelayCommand Class for MVVM - C# and VB

Publishing both C# and VB version of the RelayCommand by Josh Smith


Namespace ApplicationClass

''' <summary>

''' A command whose sole purpose is to

''' relay its functionality to other

''' objects by invoking delegates. The

''' default return value for the CanExecute

''' method is 'true'.

''' </summary>

''' <remarks>Class taken from online example. http://msdn.microsoft.com/en-us/magazine/dd419663.aspx Josh Smith</remarks>

Public Class RelayCommand

Implements ICommand

#Region "Fields"

Private ReadOnly _execute As Action(Of Object)

Private ReadOnly _canExecute As Predicate(Of Object)

#End Region

#Region "Constructors"

''' <summary>

''' Creates a new command that can always execute.

''' </summary>

''' <param name="execute">The execution logic.</param>

Public Sub New(ByVal execute As Action(Of Object))

Me.New(execute, Nothing)

End Sub

''' <summary>

''' Creates a new command.

''' </summary>

''' <param name="execute">The execution logic.</param>

''' <param name="canExecute">The execution status logic.</param>

Public Sub New(ByVal execute As Action(Of Object), ByVal canExecute As Predicate(Of Object))

If execute Is Nothing Then

Throw New ArgumentNullException("execute")

End If

_execute = execute

_canExecute = canExecute

End Sub

#End Region

#Region "ICommand Members"

'<DebuggerStepThrough()> _

Public Function CanExecute(ByVal parameter As Object) As Boolean Implements ICommand.CanExecute

Return If(_canExecute Is Nothing, True, _canExecute(parameter))

End Function

Public Custom Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged

AddHandler(ByVal value As EventHandler)

AddHandler CommandManager.RequerySuggested, value

End AddHandler

RemoveHandler(ByVal value As EventHandler)

RemoveHandler CommandManager.RequerySuggested, value

End RemoveHandler

RaiseEvent(ByVal sender As System.Object, ByVal e As System.EventArgs)

End RaiseEvent

End Event

Public Sub Execute(ByVal parameter As Object) Implements ICommand.Execute

_execute(parameter)

End Sub

#End Region

End Class

End Namespace











using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Windows.Input;

namespace Xpert_Lync.ViewModel

{

public class RelayCommand : ICommand

{

#region Fields

readonly Action<object> _execute;

readonly Predicate<object> _canExecute;

#endregion // Fields

#region Constructors

public RelayCommand(Action<object> execute)

: this(execute, null)

{

}

public RelayCommand(Action<object> execute, Predicate<object> canExecute)

{

if (execute == null)

throw new ArgumentNullException("execute");

_execute = execute;

_canExecute = canExecute;

}

#endregion // Constructors

#region ICommand Members

 

public bool CanExecute(object parameter)

{

return _canExecute == null ? true : _canExecute(parameter);

}

public event EventHandler CanExecuteChanged

{

add { CommandManager.RequerySuggested += value; }

remove { CommandManager.RequerySuggested -= value; }

}

public void Execute(object parameter)

{

_execute(parameter);

}

#endregion // ICommand Members

}

}