Megosztás a következőn keresztül:


Útmutató: Érvényesítés megvalósítása a DataGrid-vezérlővel

A DataGrid vezérlőelem lehetővé teszi az érvényesítést mind a cella, mind a sor szintjén. A cellaszintű ellenőrzéssel egy kötött adatobjektum egyedi tulajdonságait érvényesítheti, amikor egy felhasználó frissít egy értéket. A sorszintű ellenőrzéssel teljes adatobjektumokat érvényesíthet, amikor egy felhasználó véglegesíti a sor módosításait. Testre szabott vizuális visszajelzést is adhat az érvényesítési hibákhoz, vagy használhatja a DataGrid vezérlő által biztosított alapértelmezett vizuális visszajelzést.

Az alábbi eljárások bemutatják, hogyan alkalmazhatók érvényesítési szabályok DataGrid kötésekre, és hogyan szabhatók testre a vizuális visszajelzések.

Az egyes cellaértékek ellenőrzése

  • Adjon meg egy vagy több érvényesítési szabályt az oszlophoz használt kötésen. Ez hasonló az adatok egyszerű vezérlőkben való érvényesítéséhez, a Adatkötés áttekintésecímű cikkben leírtak szerint.

    Az alábbi példa egy DataGrid vezérlőelemet mutat be, amelynek négy oszlopa egy üzleti objektum különböző tulajdonságaihoz van kötve. Három oszlop adja meg a ExceptionValidationRule úgy, hogy a ValidatesOnExceptions tulajdonságot trueértékre állítja.

    <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>
    

    Ha egy felhasználó érvénytelen értéket ad meg (például egy nem egész számot a Tanfolyamazonosító oszlopban), piros szegély jelenik meg a cella körül. Ezt az alapértelmezett érvényesítési visszajelzést az alábbi eljárásban leírtak szerint módosíthatja.

A cellaérvényesítési visszajelzés testreszabása

  • Állítsa az oszlop EditingElementStyle tulajdonságát az oszlop szerkesztési vezérlőjének megfelelő stílusra. Mivel a szerkesztési vezérlők futásidőben jönnek létre, a Validation.ErrorTemplate csatolt tulajdonságot nem tudja úgy használni, mint az egyszerű vezérlők esetében.

    Az alábbi példa úgy frissíti az előző példát, hogy hozzáad egy, a három oszlop által megosztott hibastílust érvényesítési szabályokkal. Ha egy felhasználó érvénytelen értéket ad meg, a stílus megváltoztatja a cella háttérszínét, és hozzáad egy elemleírást. Figyelje meg az eseményindító használatát annak megállapításához, hogy van-e érvényesítési hiba. Erre azért van szükség, mert jelenleg nincs dedikált hibasablon a cellákhoz.

    <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>
    

    Az oszlop által használt CellStyle lecserélésével szélesebb körű testreszabást valósíthat meg.

Több érték ellenőrzése egyetlen sorban

  1. Implementáljon egy ValidationRule alosztályt, amely a kötött adatobjektum több tulajdonságát ellenőrzi. A Validate metódus implementálásában adja át a value paraméter értékét egy BindingGroup-példányra. Ezután az adatobjektumot a Items tulajdonságon keresztül érheti el.

    Az alábbi példa ezt a folyamatot mutatja be annak ellenőrzésére, hogy egy StartDate objektum Course tulajdonságértéke korábbi-e a EndDate tulajdonságértékénél.

    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. Adja hozzá az érvényesítési szabályt a DataGrid.RowValidationRules gyűjteményhez. A RowValidationRules tulajdonság közvetlen hozzáférést biztosít egy ValidationRules példány BindingGroup tulajdonságához, amely a vezérlőelem által használt összes kötést csoportosítja.

    Az alábbi példa az XAML RowValidationRules tulajdonságát állítja be. A ValidationStep tulajdonság UpdatedValue van beállítva, így az ellenőrzés csak a kötött adatobjektum frissítése után történik.

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

    Ha egy felhasználó a kezdő dátumnál korábbi záródátumot ad meg, a sorfejlécben piros felkiáltójel (!) jelenik meg. Ezt az alapértelmezett érvényesítési visszajelzést az alábbi eljárásban leírtak szerint módosíthatja.

Sorérvényesítési visszajelzés testreszabása

  • Állítsa be a DataGrid.RowValidationErrorTemplate tulajdonságot. Ez a tulajdonság lehetővé teszi a sorérvényesítési visszajelzések testreszabását az egyes DataGrid vezérlőkhöz. Több vezérlőt is érinthet, ha implicit sorstílust használ a DataGridRow.ValidationErrorTemplate tulajdonság beállításához.

    Az alábbi példa az alapértelmezett sorérvényesítési visszajelzést egy láthatóbb mutatóra cseréli. Ha egy felhasználó érvénytelen értéket ad meg, megjelenik egy piros kör fehér felkiáltójellel a sorfejlécben. Ez sor- és cellaérvényesítési hibák esetén is előfordul. A társított hibaüzenet egy súgóablakban jelenik meg.

    <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>
    

példa

Az alábbi példa teljes bemutatót nyújt a cella- és sorérvényesítéshez. A Course osztály egy mintaadat-objektumot biztosít, amely IEditableObject valósít meg a tranzakciók támogatásához. A DataGrid vezérlő IEditableObject kommunikál, hogy a felhasználók az ESC lenyomásával visszaállíthassák a módosításokat.

Megjegyzés:

Ha Visual Basicet használ, a MainWindow.xaml első sorában cserélje le a x:Class="DataGridValidation.MainWindow"x:Class="MainWindow".

Az ellenőrzés teszteléséhez próbálkozzon az alábbiakval:

  • A Tanfolyamazonosító oszlopban adjon meg egy nem egész számot.

  • A Záró dátum oszlopban adjon meg egy, a kezdő dátumnál korábbi dátumot.

  • Törölje az értéket a tanfolyamazonosítóban, a kezdő dátumban vagy a záródátumban.

  • Érvénytelen cellaérték visszavonásához helyezze vissza a kurzort a cellába, és nyomja le az ESC billentyűt.

  • Ha egy teljes sor módosításait vissza szeretné vonni, amikor az aktuális cella szerkesztési módban van, nyomja le kétszer az ESC billentyűt.

  • Érvényesítési hiba esetén vigye az egérmutatót a sorfejléc mutatója fölé a kapcsolódó hibaüzenet megtekintéséhez.

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>

Lásd még