Showing posts with label Validation. Show all posts
Showing posts with label Validation. Show all posts

Thursday, 6 June 2013

WPF Binding Integer Validation with Null Values

I found a small hole in an application I am developing where a null value in a textbox bound to an integer value wouldn’t get validated.

It was slightly more complicated than that however. The xaml was as follows;

<TextBox Text="{Binding MyTextBoxText, UpdateSourceTrigger=LostFocus, ValidatesOnDataErrors=True, NotifyOnValidationError=True, Mode=TwoWay}"/>

Where my Validation was set for when the control lost focus.

When I added a new record, the value of the binding was set to null, this enforced by validation correctly. Same when I edited the text and left the control. However, if I edited the control when it had a value, say changing the value from a 2 to nothing, then the validation wouldn’t occur.

This was because the binding didn’t have a value for a null entry. Adding a TargetNullValue parameter to the binding and thus changing the binding to the following fixed the issue nicely;



<TextBox Text="{Binding TaskOrder, UpdateSourceTrigger=LostFocus, ValidatesOnDataErrors=True, NotifyOnValidationError=True, Mode=TwoWay, TargetNullValue=''}"/>

More information on the TargetNullValue Property can be found here;

http://msdn.microsoft.com/en-us/library/system.windows.data.bindingbase.targetnullvalue.aspx

Sunday, 3 February 2013

WPF Error Adorner Visibility Binding MVVM Style

While working on an Application for a Client recently, I found that I needed to be able to control the visibility of the WPF Error Adorners.

These error adorners are a great way of giving the end user a visual representation of where any Validation Errors exist. However, as a result of their design, these Adorners will always appear ontop of all other elements. This causes a problem of course, when using anything such as a Customer Message box. The very thing required to notify the User of any Validation Errors on Save for example.

So, I decided to look at ways of controlling, globally, the Visibility of the Error Adorners. This became rather troublesome, After some trial and error I realised that I could reach the DataContext that the Error Adorner was placed within by refering to the AdornedElement’s Parent.

Once I realised this, I added a ShowErrors Boolean Property to my DataContext, and bound the Visibility of the AdornedElement to this.

The XAML Code was;

<Converters:BolVisibilityConverter x:Key="MyBolVisibilityConverter"/>
<Style TargetType="{x:Type TextBox}">
      <Setter Property="VerticalAlignment" Value="Center" />
      <Setter Property="Margin" Value="0,2,40,2" />
      <Setter Property="Validation.ErrorTemplate">
          <Setter.Value>
              <ControlTemplate>
                        <DockPanel LastChildFill="true" Visibility="{Binding ElementName=customAdorner, Path=AdornedElement.Parent.DataContext.ShowErrors, Converter={StaticResource MyBolVisibilityConverter}, Mode=TwoWay}">
                            <Border Background="Red" DockPanel.Dock="right" Margin="5,0,0,0" Width="20" Height="20" CornerRadius="10"
                            ToolTip="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
                                <TextBlock Text="!" VerticalAlignment="center" HorizontalAlignment="center" FontWeight="Bold" Foreground="white">
                                </TextBlock>
                          </Border>
                          <AdornedElementPlaceholder Name="customAdorner" VerticalAlignment="Center" >
                         <Border BorderBrush="red" BorderThickness="1" />
                       </AdornedElementPlaceholder>
                   </DockPanel>
               </ControlTemplate>
           </Setter.Value>
      </Setter>
</Style>


I needed to use a Value Converter here, to convert my Boolean to a Visibility Value. The Converter Code was;



Namespace Converters
 
    Public Class BolVisibilityConverter
        Implements IValueConverter
 
        Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As Globalization.CultureInfo) As Object Implements IValueConverter.Convert
 
            If value Is Nothing OrElse value = False Then
 
                Return Visibility.Hidden
 
            Else
 
                Return Visibility.Visible
 
            End If
 
        End Function
 
        Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As Globalization.CultureInfo) As Object Implements IValueConverter.ConvertBack
            Return DirectCast(value, Boolean)
 
        End Function
    End Class
 
End Namespace

I was then able to control the Adorner Visibility simply by setting the ShowErrors Property to either True or False

Monday, 21 January 2013

Forcing html Input element to Numeric Only Input

While developing a shopping cart function for a client, I needed to restrict the user to entering numbers only in an Input field

I came across this handy post;

http://www.itjungles.com/javascript/how-to-use-javascript-to-force-numeric-value-in-textbox

Basically, we need to add the following function to the JavaScript section;

function isNumericKey(evt)
{
    var charCode = (evt.which) ? evt.which : event.keyCode
    if (charCode > 31 && (charCode < 48 || charCode > 57)) 
    {
        return false;
    }
    else
    {
        return true;
    }
}    


We then add the the following to your input element;


onkeypress="return isNumericKey(event)"


Hey Presto! You have a numeric only Input Element!

Monday, 7 January 2013

MVVM WPF Validating multiple items together

In an application I am developing, I required that two checkboxes be validated together, when either one of them were clicked. I also needed to only show the Validation error once in my Error Message Box.

To achieve this we first call the OnPropertyChanged routine, which in turn raises the PropertyChanged event, for each linked Property when any of the linked properties change.

For example;

Public Property Property1 As Boolean
    Get
        Return _Property1
    End Get
    Set(value As Boolean)
 
        If _Property1 <> value Then
 
            _Property1 = value
            OnPropertyChanged("Property1")
            OnPropertyChanged("Property2")
 
        End If
 
    End Set
End Property


For the Validation errors, I have employed a simple Key, Value Pair list to store all of the Validation Error Results. Thus, I simply check to see if the other Property has Registered an Error, and remove it if so;



 
        ''' <summary>
        ''' Validates the Current Item
        ''' </summary>
        ''' <param name="ColumnName"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Overrides Function ValidateItemValue(ColumnName As String) As String
            Dim strResult As String = ""
 
            Select Case ColumnName
 
                Case "Property1"
 
                    If Property1 = False And Property2 = False Then
 
                        strResult = "Please select either Property1, Propert2 or Both!"
 
                        If Me.lstErrors.ContainsKey("Property2") = True Then
 
                            Me.lstErrors.Remove("Property2")
 
                        End If
 
                    End If
 
                Case "Property2"
 
                    If Property1 = False And Property2 = False Then
 
                        strResult = "Please select either Property1, Property2 or Both!"
 
                        If Me.lstErrors.ContainsKey("Property1") = True Then
 
                            Me.lstErrors.Remove("Property1")
 
                        End If
 
                    End If
 
 
            End Select
 
            SortErrorList(ColumnName, strResult)        ' Add or Remove an Error Item
 
            Return strResult
 
        End Function

Validating an Email Address

In order to validate an email address, use the following function;

Public Function IsValidEmailAddress(ByVal EmailAddress As String) As Boolean
    Dim Expression As New System.Text.RegularExpressions.Regex("\S+@\S+\.\S+")
 
    If EmailAddress = "" Then
 
        Return True
 
    Else
 
        Return Expression.IsMatch(EmailAddress)
 
    End If
    
End Function