Alessandro Del Sole's Blog

{ A programming space about Microsoft® .NET® }
posts - 1909, comments - 2047, trackbacks - 352

My Links

News

Your host

This is me! Questo spazio è dedicato a Microsoft® .NET®, di cui sono molto appassionato :-)

Cookie e Privacy

Microsoft MVP

My MVP Profile

Microsoft Certified Professional

Microsoft Specialist

Xamarin Certified Mobile Developer

Il mio libro su VB 2015!

Pre-ordina il mio libro su VB 2015 Pre-ordina il mio libro "Visual Basic 2015 Unleashed". Clicca sulla copertina per informazioni!

Il mio libro su WPF 4.5.1!

Clicca sulla copertina per informazioni! E' uscito il mio libro "Programmare con WPF 4.5.1". Clicca sulla copertina per informazioni!

These postings are provided 'AS IS' for entertainment purposes only with absolutely no warranty expressed or implied and confer no rights.
If you're not an Italian user, please visit my English blog

Le vostre visite

I'm a VB!

Guarda la mia intervista a Seattle

Follow me on Twitter!

Altri spazi

GitHub
I miei progetti open-source su GitHub

Article Categories

Archives

Post Categories

Image Galleries

Privacy Policy

WPF: Utilizzare le validation rules con Visual Basic 2010

Uno dei più importanti requisiti quando si lavora con i dati è la validazione degli stessi, ossia la possibilità di accettarli o rigettarli a seconda della loro conformità (o meno) a determinate regole. Pensiamo, ad esempio, all'immissione di un indirizzo e-mail che non sia correttamente formato. WPF non è da meno e, proprio per tale ragione, offre degli strumenti specifici.

Sicuramente c'è l'interfaccia IDataErrorInfo e ne abbiamo visto alcuni esempi parlando di Model-View-ViewModel. In realtà WPF offre (da sempre, per la verità) una classe che si chiama ValidationRule e che consente di scrivere classi che da questa ereditano e che implementano delle regole di validazione per i nostri oggetti. Facciamo ora un esempio pratico, ossia partire da una collezione di oggetti Contact, per ciascuno dei quali vogliamo verificare la validità dell'indirizzo e-mail immesso tramite TextBox.

Ipotizziamo quindi di avere la seguente classe Contact:

Public Class Contact

    Public Property FirstName As String

    Public Property LastName As String

    Public Property Email As String

End Class

E, conseguentemente, una collezione chiamata Contacts:

 

Imports System.Collections.ObjectModel

 

Public Class Contacts

    Inherits ObservableCollection(Of Contact)

 

End Class

Ora supponiamo di voler scrivere una regola di validazione che, una volta che la collezione è in binding con l'interfaccia, verifichi la correttezza dell'indirizzo e-mail tramite regular expression:

'Richiede Imports System.Text.RegularExpressions

Public Class IsValidEmailAddressValidationRule

    Inherits ValidationRule

 

    Public Overrides Function Validate(ByVal value As Object, ByVal cultureInfo As System.Globalization.CultureInfo) _

                                       As System.Windows.Controls.ValidationResult

        Dim validateMail As String =

            "^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-z]{2,4}|[0-9]{1,3})(\]?)$"

 

        Dim result = Regex.IsMatch(CStr(value), validateMail)

 

        If result = True Then

            Return New ValidationResult(True, Nothing)

        Else

            Return New ValidationResult(False, "Non è un indirizzo email valido")

        End If

    End Function

End Class

Gli aspetti rilevanti sono i seguenti:

  • la classe eredita da ValidationRule che è una classe di tipo MustInherit
  • si ridefinisce il metodo Validate, all'interno del quale si scrive la logica di validazione vera e propria
  • il risultato della validazione è restituito tramite un oggetto chiamato ValidationResult, il cui costruttore vuole un argomento booleano che indica il successo (True) o fallimento (False) della validazione e, in caso di fallimento, un secondo argomento che contiene il messaggio di errore da inviare. In caso di successo, è sufficiente inviare Nothing

A livello di XAML, l'interfaccia dell'applicazione dimostrativa è molto banale, creata, peraltro, con l'ausilio del drag and drop. Ho aggiunto solo 2 pulsanti che consentono di spostarsi tra un record e l'altro nella collezione. Quello su cui occorre focalizzare l'attenzione è come viene definito il binding per la TextBox:

<Window x:Class="MainWindow"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     

    xmlns:local="clr-namespace:WpfApplication1"

    Title="MainWindow" Height="250" Width="325" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:my="clr-namespace:WpfApplication1">

    <Window.Resources>

        <CollectionViewSource x:Key="ContactsViewSource" d:DesignSource="{d:DesignInstance my:Contacts}" />

    </Window.Resources>

    <Grid>

        <Grid.RowDefinitions>

            <RowDefinition/>

            <RowDefinition Height="40"/>

        </Grid.RowDefinitions>

        <Grid DataContext="{StaticResource ContactsViewSource}" Name="Grid1" Margin="10" Grid.Row="0">

            <Grid.ColumnDefinitions>

                <ColumnDefinition Width="Auto" />

                <ColumnDefinition Width="Auto" />

            </Grid.ColumnDefinitions>

            <Grid.RowDefinitions>

                <RowDefinition Height="Auto" />

                <RowDefinition Height="Auto" />

                <RowDefinition Height="Auto" />

            </Grid.RowDefinitions>

            <Label Content="Email:" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />

            <TextBox Grid.Column="1" Grid.Row="0" Height="23" HorizontalAlignment="Left" Margin="3" Name="EmailTextBox"

                     VerticalAlignment="Center" Width="120">

                <!-- Definisco l'elemento Text in modo gerarchico-->

                <TextBox.Text>

                    <!-- Definisco il binding-->

                    <Binding Path="Email" Mode="TwoWay" ValidatesOnExceptions="True" NotifyOnValidationError="True">

                        <!-- e all'intero del binding immetto la Validation Rule-->

                        <Binding.ValidationRules>

                            <!-- local è un namespace Xml definito all'inizio

                                 e che punta all'assembly corrente-->

                            <local:IsValidEmailAddressValidationRule/>

                        </Binding.ValidationRules>

                    </Binding>

                </TextBox.Text>

            </TextBox>

            <Label Content="First Name:" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />

            <TextBox Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="3" Name="FirstNameTextBox" Text="{Binding Path=FirstName, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />

            <Label Content="Last Name:" Grid.Column="0" Grid.Row="2" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />

            <TextBox Grid.Column="1" Grid.Row="2" Height="23" HorizontalAlignment="Left" Margin="3" Name="LastNameTextBox" Text="{Binding Path=LastName, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />

        </Grid>

        <StackPanel Orientation="Horizontal" Grid.Row="1">

            <Button Name="NextButton" Width="80" Height="30" Margin="5" Content="Next"/>

            <Button Name="PrevButton" Width="80" Height="30" Margin="5" Content="Previous"/>

        </StackPanel>

    </Grid>

</Window>

Come vedete, all'interno del Binding viene nidificato il riferimento alla regola di validazione definita nel codice. Il code-behind è il seguente:

Imports System.ComponentModel

 

Class MainWindow

 

    Private myContacts As New Contacts

    Private ContactsViewSource As CollectionViewSource

 

    Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded

        LoadSomeData()

 

        ContactsViewSource = CType(Me.FindResource("ContactsViewSource"), System.Windows.Data.CollectionViewSource)

        'Assegno la sorgente dati

        ContactsViewSource.Source = myContacts

 

    End Sub

 

    'Creo dei dati fittizi da mostrare

    Private Sub LoadSomeData()

        Dim c1 As New Contact With {.FirstName = "Alessandro", .LastName = "Del Sole", .Email = "alessandro.delsole@visual-basic.it"}

        myContacts.Add(c1)

    End Sub

 

    Private Sub NextButton_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles NextButton.Click

        'Verifico che il controllo non contenga errori

        If Validation.GetHasError(Me.EmailTextBox) Then

            MessageBox.Show("Mi spiace, ma finchè non risolvi il problema non puoi andare avanti")

        Else

            Me.ContactsViewSource.View.MoveCurrentToNext()

        End If

    End Sub

 

    Private Sub PrevButton_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles PrevButton.Click

        Me.ContactsViewSource.View.MoveCurrentToPrevious()

    End Sub

End Class

Notate come sia possibile ottenere da codice la presenza di errori di validazione utilizzando il metodo statico Validation.GetHasErrors che va a recuperare il valore dell'attached property Validation.HasErrors del controllo che emette la validazione. In questo modo possiamo decidere se bloccare successive azioni finché non vengono fatte delle correzioni. Il risultato a runtime è il seguente:

Finché l'errore non verrà corretto, il pulsante Next non permetterà di andare avanti. Come potete osservare il controllo viene bordato di rosso e questo è il template di default. Come sempre nello stile di WPF, questi template possono essere ridefiniti mediante modifica dell'ErrorTemplate, cosa che avevamo già fatto nella serie su MVVM e di cui trovate un esempio in questo post.

Le Validation Rules in WPF permettono anche di intercettare eccezioni del CLR e di mostrare errori di validazione utilizzando un oggetto chiamato ExceptionValidationRule, che si usa in questo modo:

                        <Binding.ValidationRules>

                            <ExceptionValidationRules/>

                        </Binding.ValidationRules>

o, più semplicemente, in questo modo:    <Binding ... ValidatesOnExceptions="True">

Quindi abbiamo visto un'alternativa interessante e tipicamente WPF per validare i nostri dati.

Alessandro

Print | posted on martedì 14 settembre 2010 21:03 | Filed Under [ Visual Basic Windows Presentation Foundation ]

Powered by:
Powered By Subtext Powered By ASP.NET