Freigeben über


Vorgehensweise: Implementieren der Validierung mit dem DataGrid-Steuerelement

Mit dem DataGrid-Steuerelement können Sie sowohl auf Zellen- als auch Zeilenebene eine Überprüfung durchführen. Mit der Überprüfung auf Zellenebene überprüfen Sie einzelne Eigenschaften eines gebundenen Datenobjekts, wenn ein Benutzer einen Wert aktualisiert. Mit der Überprüfung auf Zeilenebene überprüfen Sie ganze Datenobjekte, wenn ein Benutzer Änderungen an einer Zeile festschreibt. Sie können auch angepasstes visuelles Feedback für Validierungsfehler bereitstellen oder das standardmäßige visuelle Feedback verwenden, das das DataGrid-Steuerelement bereitstellt.

Die folgenden Verfahren beschreiben, wie Validierungsregeln auf die DataGrid-Bindungen angewendet werden, um das visuelle Feedback anzupassen.

Um einzelne Zellwerte zu validieren

  • Definieren Sie eine oder mehrere Validierungsregeln für die Bindung, die für eine Spalte verwendet wird. Dies ähnelt dem Überprüfen von Daten in einfachen Steuerelementen, wie in Datenbindungsübersichtbeschrieben.

    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 Sie die eigenschaft ValidatesOnExceptions auf truefestlegen.

    <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 eingibt (z. B. eine nicht ganze Zahl in der Spalte "Kurs-ID"), wird um die Zelle ein roter Rahmen angezeigt. Sie können dieses Standardüberprüfungsfeedback wie im folgenden Verfahren beschrieben ändern.

Zum Anpassen des Feedbacks zur Zellüberprüfung

  • Legen Sie die Eigenschaft EditingElementStyle der Spalte auf einen Stil fest, der für das Bearbeitungssteuerelement der Spalte geeignet ist. Da die Bearbeitungssteuerelemente zur Laufzeit erstellt werden, können Sie die angefügte Validation.ErrorTemplate Eigenschaft nicht wie bei einfachen Steuerelementen verwenden.

    Im folgenden Beispiel wird das vorherige Beispiel aktualisiert, indem ein Fehlerformat hinzugefügt wird, das von den drei Spalten mit Gültigkeitsprüfungsregeln gemeinsam verwendet wird. Wenn ein Benutzer einen ungültigen Wert eingibt, ändert der Stil die Hintergrundfarbe der Zelle und zeigt eine QuickInfo an. Beachten Sie die Verwendung eines Triggers, um festzustellen, ob ein Überprüfungsfehler vorliegt. Dies ist erforderlich, da derzeit keine dedizierte 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 vornehmen, indem Sie das von der Spalte verwendete "CellStyle" ersetzen.

So überprüfen Sie mehrere Werte in einer einzelnen Zeile

  1. Implementieren Sie eine ValidationRule-Unterklasse, die mehrere Eigenschaften des gebundenen Datenobjekts überprüft. In der Implementierung Ihrer Validate-Methode den Wert des Parameters value in eine Instanz von BindingGroup umwandeln. Anschließend können Sie über die eigenschaft Items auf das Datenobjekt zugreifen.

    Im folgenden Beispiel wird dieser Prozess veranschaulicht, um zu überprüfen, ob der Wert der StartDate-Eigenschaft für ein Course-Objekt vor dem Eigenschaftswert EndDate liegt.

    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
    
  2. Fügen Sie der DataGrid.RowValidationRules-Auflistung die Validierungsregel hinzu. Die RowValidationRules-Eigenschaft bietet direkten Zugriff auf die ValidationRules-Eigenschaft einer BindingGroup Instanz, die alle vom Steuerelement verwendeten Bindungen gruppiert.

    Im folgenden Beispiel wird die "RowValidationRules"-Eigenschaft in XAML festgelegt. Die ValidationStep-Eigenschaft wird auf UpdatedValue festgelegt, sodass die Überprüfung erst erfolgt, nachdem das gebundene Datenobjekt aktualisiert wurde.

    <DataGrid.RowValidationRules>
      <local:CourseValidationRule ValidationStep="UpdatedValue"/>
    </DataGrid.RowValidationRules>
    

    Wenn ein Benutzer ein Enddatum angibt, das vor dem Startdatum liegt, wird in der Zeilenüberschrift ein rotes Ausrufezeichen (!) angezeigt. Sie können dieses Standardüberprüfungsfeedback wie im folgenden Verfahren beschrieben ändern.

So passen Sie das Feedback zur Zeilenüberprüfung an

  • Legen Sie die eigenschaft DataGrid.RowValidationErrorTemplate fest. Mit dieser Eigenschaft können Sie das Feedback zur Zeilenüberprüfung für einzelne DataGrid Steuerelemente anpassen. Sie können auch mehrere Steuerelemente beeinflussen, indem Sie einen impliziten Zeilenstil verwenden, um die Eigenschaft DataGridRow.ValidationErrorTemplate festzulegen.

    Im folgenden Beispiel wird das Standardmäßige Zeilenüberprüfungsfeedback durch einen sichtbareren Indikator ersetzt. Wenn ein Benutzer einen ungültigen Wert eingibt, wird in der Zeilenüberschrift ein roter Kreis mit einem weißen Ausrufezeichen angezeigt. Dies tritt für Zeilen- und 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

Im folgenden Beispiel wird eine vollständige Demonstration für die Zell- und Zeilenüberprüfung bereitgestellt. Die Course-Klasse stellt ein Beispieldatenobjekt bereit, das IEditableObject implementiert, um Transaktionen zu unterstützen. Das DataGrid-Steuerelement interagiert mit IEditableObject, um Benutzern das Zurücksetzen von Änderungen durch Drücken von ESC zu ermöglichen.

Anmerkung

Wenn Sie Visual Basic verwenden, ersetzen Sie in der ersten Zeile von "MainWindow.xaml" x:Class="DataGridValidation.MainWindow" durch x:Class="MainWindow".

Um die Überprüfung zu testen, versuchen Sie Folgendes:

  • Geben Sie in der Spalte "Kurs-ID" einen Wert ohne ganze Zahl ein.

  • Geben Sie in der Spalte "Enddatum" ein Datum ein, das vor dem Startdatum liegt.

  • Löschen Sie den Wert in "Kurs-ID", "Startdatum" oder "Enddatum".

  • 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 Überprüfungsfehler 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>

Siehe auch