Como implementar validação com o controle DataGrid
O DataGrid controle permite que você execute a validação no nível da célula e da linha. Com a validação no nível da célula, você valida propriedades individuais de um objeto com associação de dados quando um usuário atualiza um valor. Com a validação no nível da linha, você valida objetos de dados inteiros quando um usuário confirma alterações em uma linha. Você também pode fornecer feedback visual personalizado para erros de validação ou usar o feedback visual padrão fornecido DataGrid pelo controle.
Os procedimentos a seguir descrevem como aplicar regras de validação a DataGrid associações e personalizar o feedback visual.
Para validar valores de células individuais
Especifique uma ou mais regras de validação para a associação usada com uma coluna. Isso é semelhante à validação de dados em controles simples, conforme descrito em Visão geral da associação de dados.
O exemplo a seguir mostra um controle com quatro colunas vinculadas a propriedades diferentes de um DataGrid objeto comercial. Três das colunas especificam o ExceptionValidationRule definindo a ValidatesOnExceptions propriedade como
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>
Quando um usuário insere um valor inválido (como um número não inteiro na coluna de ID do Curso), uma borda vermelha aparece em torno da célula. É possível alterar esses comentários de validação padrão conforme descrito no procedimento a seguir.
Para personalizar os comentários de validação de célula
Defina a propriedade da EditingElementStyle coluna como um estilo apropriado para o controle de edição da coluna. Como os controles de edição são criados em tempo de execução, você não pode usar a propriedade anexada Validation.ErrorTemplate como faria com controles simples.
O exemplo a seguir atualiza o exemplo anterior adicionando um estilo de erro compartilhado pelas três colunas com regras de validação. Quando um usuário insere um valor inválido, o estilo altera a cor da tela de fundo da célula e adiciona uma dica de ferramenta. Observe o uso de um gatilho para determinar se há um erro de validação. Isso é necessário porque atualmente não há um modelo de erro dedicado para células.
<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>
Você pode implementar uma personalização mais extensa substituindo a CellStyle usada pela coluna.
Para validar vários valores em uma única linha
Implemente uma ValidationRule subclasse que verifica várias propriedades do objeto de dados vinculado. Validate Na implementação do método, converta o valor do
value
parâmetro em uma BindingGroup instância. Em seguida, você pode acessar o objeto de dados por meio da Items propriedade.O exemplo a seguir demonstra esse processo para validar se o valor da propriedade
StartDate
para um objetoCourse
é anterior ao valor de sua propriedadeEndDate
.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
Adicione a regra de validação à DataGrid.RowValidationRules coleção. A RowValidationRules propriedade fornece acesso direto à ValidationRules propriedade de uma BindingGroup instância que agrupa todas as associações usadas pelo controle.
O exemplo a seguir define a RowValidationRules propriedade em XAML. A ValidationStep propriedade é definida como UpdatedValue para que a validação ocorra somente depois que o objeto de dados acoplado for atualizado.
<DataGrid.RowValidationRules> <local:CourseValidationRule ValidationStep="UpdatedValue"/> </DataGrid.RowValidationRules>
Quando um usuário especificar uma data de término anterior à data de início, um ponto de exclamação vermelho (!) será exibido no cabeçalho da linha. É possível alterar esses comentários de validação padrão conforme descrito no procedimento a seguir.
Para personalizar os comentários de validação de linha
Definir a propriedade DataGrid.RowValidationErrorTemplate. Essa propriedade permite personalizar comentários de validação de linha para controles individuais DataGrid . Você também pode afetar vários controles usando um estilo de linha implícito para definir a DataGridRow.ValidationErrorTemplate propriedade.
O exemplo a seguir substitui os comentários de validação de linha padrão por um indicador mais visível. Quando um usuário insere um valor inválido, um círculo vermelho com um ponto de exclamação branco aparece no cabeçalho da linha. Isso ocorre para erros de validação de linha e de célula. A mensagem de erro associada é exibida em uma dica de ferramenta.
<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>
Exemplo
O exemplo a seguir fornece uma demonstração completa da validação de linha e de célula. A Course
classe fornece um objeto de dados de exemplo que implementa IEditableObject para dar suporte a transações. O DataGrid controle interage com IEditableObject para permitir que os usuários revertam as alterações pressionando ESC.
Observação
Se você estiver usando o Visual Basic, na primeira linha de MainWindow.xaml, substitua x:Class="DataGridValidation.MainWindow"
por x:Class="MainWindow"
.
Para testar a validação, tente o seguinte:
Na coluna ID do Curso, insira um valor não inteiro.
Na coluna Data de Término, insira uma data anterior à Data de Início.
Exclua o valor de ID do C, Data de Início ou Data de Término.
Para desfazer um valor de célula inválido, coloque o cursor novamente na célula e pressione a tecla ESC.
Para desfazer alterações em uma linha inteira quando a célula atual estiver no modo de edição, pressione a tecla ESC duas vezes.
Quando um erro de validação ocorrer, mova o ponteiro do mouse sobre o indicador no cabeçalho da linha para ver a mensagem de erro associada.
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>
Confira também
.NET Desktop feedback