Vorgehensweise: Implementieren von Validierung mit dem DataGrid-Steuerelement
Mit dem DataGrid-Steuerelement können Sie sowohl auf Zellenebene als auch auf Zeilenebene Validierungen durchführen. Mit der Validierung auf Zellebene überprüfen Sie einzelne Eigenschaften eines gebundenen Datenobjekts, wenn ein Benutzer einen Wert ändert. Mit der Validierung auf Zeilenebene überprüfen Sie ganze Datenobjekte, wenn ein Benutzer Änderungen an einer Zeile anwendet. Sie können auch angepasstes visuelles Feedback für Validierungsfehler bereitstellen oder das standardmäßige visuelle Feedback verwenden, das vom DataGrid-Steuerelement bereitgestellt wird.
In den folgenden Verfahren wird beschrieben, wie Gültigkeitsregeln auf DataGrid-Bindungen angewendet werden und das visuelle Feedback angepasst wird.
So überprüfen Sie einzelne Zellwerte
Geben Sie mindestens eine Validierungsregel für die Bindung an, die mit einer Spalte verwendet wird. Dies ähnelt der Überprüfung von Daten in einfachen Steuerelementen, wie unter Übersicht über die Datenbindung beschrieben.
Das folgende Beispiel zeigt ein DataGrid-Steuerelement mit vier Spalten, die an unterschiedliche Eigenschaften eines Geschäftsobjekts gebunden sind. Drei der Spalten geben die ExceptionValidationRule an, indem die Eigenschaft ValidatesOnExceptions auf
true
gesetzt wird.<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>
Wenn ein Benutzer einen ungültigen Wert (z. B. eine nicht ganze Zahl in der Spalte „Kurs-ID“) eingibt, wird um die Zelle ein roter Rahmen angezeigt. Sie können dieses standardmäßige Validierungsfeedback ändern wie im folgenden Verfahren beschrieben.
Vorgehen zum Anpassen des Feedbacks der Zellvalidierung
Legen Sie die Eigenschaft EditingElementStyle der Spalte auf einen Stil fest, die für das Bearbeitungssteuerelement der Spalte geeignet ist. Da die Bearbeitungssteuerelemente zur Laufzeit erstellt werden, können Sie die angefügte Eigenschaft Validation.ErrorTemplate nicht wie bei einfachen Steuerelementen verwenden.
Das folgende Beispiel aktualisiert das vorherige Beispiel aktualisiert, indem ein Fehlerstil hinzugefügt wird, der von den drei Spalten mit Validierungsregeln gemeinsam genutzt wird. Wenn ein Benutzer einen ungültigen Wert eingibt, ändert die Formatvorlage die Zellenhintergrundfarbe und fügt eine QuickInfo hinzu. Beachten Sie die Verwendung eines Triggers, um festzustellen, ob ein Validierungsfehler vorliegt. Dies ist erforderlich, da derzeit keine eigene Fehlervorlage für Zellen vorhanden ist.
<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>
Sie können umfangreichere Anpassungen implementieren, indem Sie den von der Spalte verwendeten CellStyle ersetzen.
Vorgehen zum Validieren mehrerer Werte in einer einzelnen Zeile
Implementieren Sie eine ValidationRule-Unterklasse, die mehrere Eigenschaften des gebundenen Datenobjekts überprüft. Wandeln Sie in ihrer Implementierung der Validate-Methoden den Parameterwert
value
in eine Instanz von BindingGroup um. Anschließend können Sie über die Items-Eigenschaft auf das Datenobjekt zugreifen.Im folgenden Beispiel wird dieser Prozess veranschaulicht. Es wird überprüft, ob der Eigenschaftswert
StartDate
für einCourse
-Objekt früher als sein EigenschaftswertEndDate
ist.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
Fügen Sie die Validierungsregel zur Sammlung DataGrid.RowValidationRules hinzu. Die Eigenschaft RowValidationRules bietet direkten Zugriff auf die Eigenschaft ValidationRules einer BindingGroup-Instanz, die alle Bindungen gruppiert, die vom Steuerelement verwendet werden.
Im folgenden Beispiel wird die RowValidationRules-Eigenschaft in XAML festgelegt. Die Eigenschaft ValidationStep wird auf UpdatedValue festgelegt, sodass die Validierung erst geschieht, nachdem das gebundene Datenobjekt aktualisiert wurde.
<DataGrid.RowValidationRules> <local:CourseValidationRule ValidationStep="UpdatedValue"/> </DataGrid.RowValidationRules>
Wenn ein Benutzer ein Enddatum angibt, das älter als das Startdatum ist, wird in der Zeilenüberschrift ein rotes Ausrufezeichen (!) angezeigt. Sie können dieses standardmäßige Validierungsfeedback ändern wie im folgenden Verfahren beschrieben.
Vorgehen zum Anpassen des Feedbacks der Zeilenvalidierung
Legen Sie die DataGrid.RowValidationErrorTemplate-Eigenschaft fest. Mit dieser Eigenschaft können Sie das Feedback zur Zeilenvalidierung für einzelne DataGrid-Steuerelemente anpassen. Sie können auch mehrere Steuerelemente beeinflussen, indem Sie einen implizite Zeilenstil verwenden, um die DataGridRow.ValidationErrorTemplate-Eigenschaft festzulegen.
Im folgenden Beispiel wird das standardmäßige Zeilenvalidierungsfeedback durch einen besser sichtbaren Indikator ersetzt. Wenn ein Benutzer einen ungültigen Wert eingibt, erscheint in der Zeilenüberschrift ein roter Kreis mit einem weißen Ausrufezeichen. Dies tritt sowohl für Zeilen- als auch für Zellüberprüfungsfehler auf. Die zugehörige Fehlermeldung wird in einer QuickInfo angezeigt.
<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>
Beispiel
Das folgende Beispiel ist eine vollständige Demonstration für die Zell- und Zeilenvalidierung. Die Course
-Klasse stellt ein Beispieldatenobjekt bereit, das zur Unterstützung von Transaktionen IEditableObject implementiert. Das DataGrid-Steuerelement interagiert mit IEditableObject, um Benutzern das Zurücksetzen von Änderungen durch Drücken von ESC zu ermöglichen.
Hinweis
Wenn Sie Visual Basic verwenden, ersetzen Sie x:Class="DataGridValidation.MainWindow"
in der ersten Zeile von MainWindow.xaml durch x:Class="MainWindow"
.
Führen Sie die folgenden Schritte aus, um die Validierung zu testen:
Geben Sie in der Spalte „Course ID“ einen nicht ganzzahligen Wert ein.
Geben Sie in der Spalte „End Date“ ein Datum ein, das vor dem „Start Date“ liegt.
Löschen Sie den Wert in „Course ID“, „Start Date“ oder „End Date“.
Um einen ungültigen Zellwert rückgängig zu machen, setzen Sie den Cursor wieder in die Zelle, und drücken Sie die ESC-Taste.
Um Änderungen für eine ganze Zeile rückgängig zu machen, wenn sich die aktuelle Zelle im Bearbeitungsmodus befindet, drücken Sie zweimal die ESC-TASTE.
Wenn ein Validierungsfehler auftritt, bewegen Sie den Mauszeiger über den Indikator in der Zeilenüberschrift, um die zugehörige Fehlermeldung anzuzeigen.
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>
Weitere Informationen
.NET Desktop feedback