Guide pratique pour implémenter la validation avec le contrôle DataGrid
Le contrôle DataGrid vous permet d’effectuer la validation au niveau de la cellule et de la ligne. Avec la validation au niveau de la cellule, vous validez les propriétés individuelles d’un objet de données lié lorsqu’un utilisateur met à jour une valeur. Avec la validation au niveau des lignes, vous validez l’intégralité des objets de données lorsqu’un utilisateur valide les modifications apportées à une ligne. Vous pouvez également fournir des commentaires visuels personnalisés pour les erreurs de validation ou utiliser les commentaires visuels par défaut fournis par le contrôle DataGrid.
Les procédures suivantes décrivent comment appliquer des règles de validation aux liaisons DataGrid et personnaliser les commentaires visuels.
Pour valider les valeurs de cellule individuelles
Spécifiez une ou plusieurs règles de validation sur la liaison utilisée avec une colonne. Cela est similaire à la validation des données dans des contrôles simples, comme décrit dans Vue d’ensemble de la liaison de données.
L’exemple suivant montre un contrôle DataGrid avec quatre colonnes liées à différentes propriétés d’un objet métier. Trois des colonnes spécifient la ExceptionValidationRule en définissant la propriété ValidatesOnExceptions à
true
.<Grid> <Grid.Resources> <local:Courses x:Key="courses"/> </Grid.Resources> <DataGrid Name="dataGrid1" FontSize="20" ItemsSource="{StaticResource courses}" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTextColumn Header="Course Name" Binding="{Binding Name, TargetNullValue=(enter a course name)}"/> <DataGridTextColumn Header="Course ID" Binding="{Binding Id, ValidatesOnExceptions=True}"/> <DataGridTextColumn Header="Start Date" Binding="{Binding StartDate, ValidatesOnExceptions=True, StringFormat=d}"/> <DataGridTextColumn Header="End Date" Binding="{Binding EndDate, ValidatesOnExceptions=True, StringFormat=d}"/> </DataGrid.Columns> </DataGrid> </Grid>
Lorsqu’un utilisateur entre une valeur non valide (par exemple, un non-entier dans la colonne ID de cours), une bordure rouge apparaît autour de la cellule. Vous pouvez modifier ces commentaires de validation par défaut, comme décrit dans la procédure suivante.
Pour personnaliser le retour de validation des cellules
Définissez la propriété EditingElementStyle de la colonne sur un style approprié pour le contrôle d’édition de la colonne. Étant donné que les contrôles d’édition sont créés au moment de l’exécution, vous ne pouvez pas utiliser la propriété jointe Validation.ErrorTemplate comme vous le feriez avec des contrôles simples.
L’exemple suivant met à jour l’exemple précédent en ajoutant un style d’erreur partagé par les trois colonnes avec des règles de validation. Lorsqu’un utilisateur entre une valeur non valide, le style modifie la couleur d’arrière-plan de la cellule et ajoute une info-bulle. Notez l’utilisation d’un déclencheur pour déterminer s’il existe une erreur de validation. Cela est nécessaire, car il n’existe actuellement aucun modèle d’erreur dédié pour les cellules.
<DataGrid.Resources> <Style x:Key="errorStyle" TargetType="{x:Type TextBox}"> <Setter Property="Padding" Value="-2"/> <Style.Triggers> <Trigger Property="Validation.HasError" Value="True"> <Setter Property="Background" Value="Red"/> <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/> </Trigger> </Style.Triggers> </Style> </DataGrid.Resources> <DataGrid.Columns> <DataGridTextColumn Header="Course Name" Binding="{Binding Name, TargetNullValue=(enter a course name)}"/> <DataGridTextColumn Header="Course ID" EditingElementStyle="{StaticResource errorStyle}" Binding="{Binding Id, ValidatesOnExceptions=True}"/> <DataGridTextColumn Header="Start Date" EditingElementStyle="{StaticResource errorStyle}" Binding="{Binding StartDate, ValidatesOnExceptions=True, StringFormat=d}"/> <DataGridTextColumn Header="End Date" EditingElementStyle="{StaticResource errorStyle}" Binding="{Binding EndDate, ValidatesOnExceptions=True, StringFormat=d}"/> </DataGrid.Columns>
Vous pouvez implémenter une personnalisation plus étendue en remplaçant la CellStyle utilisée par la colonne.
Pour valider plusieurs valeurs dans une seule ligne
Implémentez une sous-classe ValidationRule qui vérifie plusieurs propriétés de l’objet de données lié. Dans votre implémentation de méthode Validate, convertissez la valeur du paramètre
value
en une instance de BindingGroup. Vous pouvez ensuite accéder à l’objet de données via la propriété Items.L’exemple suivant illustre ce processus pour vérifier si la valeur de propriété
StartDate
d’un objetCourse
est antérieure à sa valeur de propriétéEndDate
.public class CourseValidationRule : ValidationRule { public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo) { Course course = (value as BindingGroup).Items[0] as Course; if (course.StartDate > course.EndDate) { return new ValidationResult(false, "Start Date must be earlier than End Date."); } else { return ValidationResult.ValidResult; } } }
Public Class CourseValidationRule Inherits ValidationRule Public Overrides Function Validate(ByVal value As Object, _ ByVal cultureInfo As System.Globalization.CultureInfo) _ As ValidationResult Dim course As Course = _ CType(CType(value, BindingGroup).Items(0), Course) If course.StartDate > course.EndDate Then Return New ValidationResult(False, _ "Start Date must be earlier than End Date.") Else Return ValidationResult.ValidResult End If End Function End Class
Ajoutez la règle de validation à la collection DataGrid.RowValidationRules. La propriété RowValidationRules fournit un accès direct à la propriété ValidationRules d’une instance BindingGroup qui regroupe toutes les liaisons utilisées par le contrôle.
L’exemple suivant définit la propriété RowValidationRules en XAML. La propriété ValidationStep est définie sur UpdatedValue afin que la validation se produise uniquement après la mise à jour de l’objet de données lié.
<DataGrid.RowValidationRules> <local:CourseValidationRule ValidationStep="UpdatedValue"/> </DataGrid.RowValidationRules>
Lorsqu’un utilisateur spécifie une date de fin antérieure à la date de début, un point d’exclamation rouge ( !) apparaît dans l’en-tête de ligne. Vous pouvez modifier ces commentaires de validation par défaut, comme décrit dans la procédure suivante.
Pour personnaliser la rétroaction de validation des lignes
Définissez la propriété DataGrid.RowValidationErrorTemplate. Cette propriété vous permet de personnaliser les commentaires de validation de ligne pour les contrôles individuels de DataGrid. Vous pouvez également affecter plusieurs contrôles à l’aide d’un style de ligne implicite pour définir la propriété DataGridRow.ValidationErrorTemplate.
L’exemple suivant remplace les commentaires de validation de ligne par défaut par un indicateur plus visible. Lorsqu’un utilisateur entre une valeur non valide, un cercle rouge avec un point d’exclamation blanc apparaît dans l’en-tête de ligne. Cela se produit pour les erreurs de validation de ligne et de cellule. Le message d’erreur associé s’affiche dans une info-bulle.
<DataGrid.RowValidationErrorTemplate> <ControlTemplate> <Grid Margin="0,-2,0,-2" ToolTip="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridRow}}, Path=(Validation.Errors)[0].ErrorContent}"> <Ellipse StrokeThickness="0" Fill="Red" Width="{TemplateBinding FontSize}" Height="{TemplateBinding FontSize}" /> <TextBlock Text="!" FontSize="{TemplateBinding FontSize}" FontWeight="Bold" Foreground="White" HorizontalAlignment="Center" /> </Grid> </ControlTemplate> </DataGrid.RowValidationErrorTemplate>
Exemple
L’exemple suivant fournit une démonstration complète pour la validation des cellules et des lignes. La classe Course
fournit un exemple d’objet de données qui implémente IEditableObject pour prendre en charge les transactions. Le contrôle DataGrid interagit avec IEditableObject pour permettre aux utilisateurs de rétablir les modifications en appuyant sur Échap.
Note
Si vous utilisez Visual Basic, dans la première ligne de MainWindow.xaml, remplacez x:Class="DataGridValidation.MainWindow"
par x:Class="MainWindow"
.
Pour tester la validation, essayez ce qui suit :
Dans la colonne ID de cours, entrez une valeur non entière.
Dans la colonne Date de fin, entrez une date antérieure à la date de début.
Supprimez la valeur dans l’ID de cours, la date de début ou la date de fin.
Pour annuler une valeur de cellule non valide, replacez le curseur dans la cellule et appuyez sur la touche Échap.
Pour annuler les modifications d’une ligne entière lorsque la cellule active est en mode Édition, appuyez deux fois sur la touche Échap.
Lorsqu’une erreur de validation se produit, déplacez le pointeur de la souris sur l’indicateur dans l’en-tête de ligne pour afficher le message d’erreur associé.
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace DataGridValidation
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
dataGrid1.InitializingNewItem += (sender, e) =>
{
Course newCourse = e.NewItem as Course;
newCourse.StartDate = newCourse.EndDate = DateTime.Today;
};
}
}
public class Courses : ObservableCollection<Course>
{
public Courses()
{
this.Add(new Course
{
Name = "Learning WPF",
Id = 1001,
StartDate = new DateTime(2010, 1, 11),
EndDate = new DateTime(2010, 1, 22)
});
this.Add(new Course
{
Name = "Learning Silverlight",
Id = 1002,
StartDate = new DateTime(2010, 1, 25),
EndDate = new DateTime(2010, 2, 5)
});
this.Add(new Course
{
Name = "Learning Expression Blend",
Id = 1003,
StartDate = new DateTime(2010, 2, 8),
EndDate = new DateTime(2010, 2, 19)
});
this.Add(new Course
{
Name = "Learning LINQ",
Id = 1004,
StartDate = new DateTime(2010, 2, 22),
EndDate = new DateTime(2010, 3, 5)
});
}
}
public class Course : IEditableObject, INotifyPropertyChanged
{
private string _name;
public string Name
{
get
{
return _name;
}
set
{
if (_name == value) return;
_name = value;
OnPropertyChanged("Name");
}
}
private int _number;
public int Id
{
get
{
return _number;
}
set
{
if (_number == value) return;
_number = value;
OnPropertyChanged("Id");
}
}
private DateTime _startDate;
public DateTime StartDate
{
get
{
return _startDate;
}
set
{
if (_startDate == value) return;
_startDate = value;
OnPropertyChanged("StartDate");
}
}
private DateTime _endDate;
public DateTime EndDate
{
get
{
return _endDate;
}
set
{
if (_endDate == value) return;
_endDate = value;
OnPropertyChanged("EndDate");
}
}
#region IEditableObject
private Course backupCopy;
private bool inEdit;
public void BeginEdit()
{
if (inEdit) return;
inEdit = true;
backupCopy = this.MemberwiseClone() as Course;
}
public void CancelEdit()
{
if (!inEdit) return;
inEdit = false;
this.Name = backupCopy.Name;
this.Id = backupCopy.Id;
this.StartDate = backupCopy.StartDate;
this.EndDate = backupCopy.EndDate;
}
public void EndEdit()
{
if (!inEdit) return;
inEdit = false;
backupCopy = null;
}
#endregion
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
public class CourseValidationRule : ValidationRule
{
public override ValidationResult Validate(object value,
System.Globalization.CultureInfo cultureInfo)
{
Course course = (value as BindingGroup).Items[0] as Course;
if (course.StartDate > course.EndDate)
{
return new ValidationResult(false,
"Start Date must be earlier than End Date.");
}
else
{
return ValidationResult.ValidResult;
}
}
}
}
Imports System.Collections.ObjectModel
Imports System.ComponentModel
Public Class MainWindow
Private Sub dataGrid1_InitializingNewItem(ByVal sender As System.Object, _
ByVal e As System.Windows.Controls.InitializingNewItemEventArgs) _
Handles dataGrid1.InitializingNewItem
Dim newCourse As Course = CType(e.NewItem, Course)
newCourse.StartDate = DateTime.Today
newCourse.EndDate = DateTime.Today
End Sub
End Class
Public Class Courses
Inherits ObservableCollection(Of Course)
Sub New()
Me.Add(New Course With { _
.Name = "Learning WPF", _
.Id = 1001, _
.StartDate = New DateTime(2010, 1, 11), _
.EndDate = New DateTime(2010, 1, 22) _
})
Me.Add(New Course With { _
.Name = "Learning Silverlight", _
.Id = 1002, _
.StartDate = New DateTime(2010, 1, 25), _
.EndDate = New DateTime(2010, 2, 5) _
})
Me.Add(New Course With { _
.Name = "Learning Expression Blend", _
.Id = 1003, _
.StartDate = New DateTime(2010, 2, 8), _
.EndDate = New DateTime(2010, 2, 19) _
})
Me.Add(New Course With { _
.Name = "Learning LINQ", _
.Id = 1004, _
.StartDate = New DateTime(2010, 2, 22), _
.EndDate = New DateTime(2010, 3, 5) _
})
End Sub
End Class
Public Class Course
Implements IEditableObject, INotifyPropertyChanged
Private _name As String
Public Property Name As String
Get
Return _name
End Get
Set(ByVal value As String)
If _name = value Then Return
_name = value
OnPropertyChanged("Name")
End Set
End Property
Private _number As Integer
Public Property Id As Integer
Get
Return _number
End Get
Set(ByVal value As Integer)
If _number = value Then Return
_number = value
OnPropertyChanged("Id")
End Set
End Property
Private _startDate As DateTime
Public Property StartDate As DateTime
Get
Return _startDate
End Get
Set(ByVal value As DateTime)
If _startDate = value Then Return
_startDate = value
OnPropertyChanged("StartDate")
End Set
End Property
Private _endDate As DateTime
Public Property EndDate As DateTime
Get
Return _endDate
End Get
Set(ByVal value As DateTime)
If _endDate = value Then Return
_endDate = value
OnPropertyChanged("EndDate")
End Set
End Property
#Region "IEditableObject"
Private backupCopy As Course
Private inEdit As Boolean
Public Sub BeginEdit() Implements IEditableObject.BeginEdit
If inEdit Then Return
inEdit = True
backupCopy = CType(Me.MemberwiseClone(), Course)
End Sub
Public Sub CancelEdit() Implements IEditableObject.CancelEdit
If Not inEdit Then Return
inEdit = False
Me.Name = backupCopy.Name
Me.Id = backupCopy.Id
Me.StartDate = backupCopy.StartDate
Me.EndDate = backupCopy.EndDate
End Sub
Public Sub EndEdit() Implements IEditableObject.EndEdit
If Not inEdit Then Return
inEdit = False
backupCopy = Nothing
End Sub
#End Region
#Region "INotifyPropertyChanged"
Public Event PropertyChanged As PropertyChangedEventHandler _
Implements INotifyPropertyChanged.PropertyChanged
Private Sub OnPropertyChanged(ByVal propertyName As String)
RaiseEvent PropertyChanged(Me, _
New PropertyChangedEventArgs(propertyName))
End Sub
#End Region
End Class
Public Class CourseValidationRule
Inherits ValidationRule
Public Overrides Function Validate(ByVal value As Object, _
ByVal cultureInfo As System.Globalization.CultureInfo) _
As ValidationResult
Dim course As Course = _
CType(CType(value, BindingGroup).Items(0), Course)
If course.StartDate > course.EndDate Then
Return New ValidationResult(False, _
"Start Date must be earlier than End Date.")
Else
Return ValidationResult.ValidResult
End If
End Function
End Class
<Window x:Class="DataGridValidation.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DataGridValidation"
Title="DataGrid Validation Example" Height="240" Width="600">
<Grid>
<Grid.Resources>
<local:Courses x:Key="courses"/>
</Grid.Resources>
<DataGrid Name="dataGrid1" FontSize="20" RowHeaderWidth="27"
ItemsSource="{StaticResource courses}"
AutoGenerateColumns="False">
<DataGrid.Resources>
<Style x:Key="errorStyle" TargetType="{x:Type TextBox}">
<Setter Property="Padding" Value="-2"/>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="Background" Value="Red"/>
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Header="Course Name"
Binding="{Binding Name, TargetNullValue=(enter a course name)}"/>
<DataGridTextColumn Header="Course ID"
EditingElementStyle="{StaticResource errorStyle}"
Binding="{Binding Id, ValidatesOnExceptions=True}"/>
<DataGridTextColumn Header="Start Date"
EditingElementStyle="{StaticResource errorStyle}"
Binding="{Binding StartDate, ValidatesOnExceptions=True,
StringFormat=d}"/>
<DataGridTextColumn Header="End Date"
EditingElementStyle="{StaticResource errorStyle}"
Binding="{Binding EndDate, ValidatesOnExceptions=True,
StringFormat=d}"/>
</DataGrid.Columns>
<DataGrid.RowValidationRules>
<local:CourseValidationRule ValidationStep="UpdatedValue"/>
</DataGrid.RowValidationRules>
<DataGrid.RowValidationErrorTemplate>
<ControlTemplate>
<Grid Margin="0,-2,0,-2"
ToolTip="{Binding RelativeSource={RelativeSource
FindAncestor, AncestorType={x:Type DataGridRow}},
Path=(Validation.Errors)[0].ErrorContent}">
<Ellipse StrokeThickness="0" Fill="Red"
Width="{TemplateBinding FontSize}"
Height="{TemplateBinding FontSize}" />
<TextBlock Text="!" FontSize="{TemplateBinding FontSize}"
FontWeight="Bold" Foreground="White"
HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</DataGrid.RowValidationErrorTemplate>
</DataGrid>
</Grid>
</Window>
Voir aussi
- DataGrid
- Grille de données
- de liaison de données
- Mettre en œuvre la validation de la liaison
- implémenter une logique de validation sur des objets personnalisés
.NET Desktop feedback