Практическое руководство. Реализация проверки с помощью элемента управления DataGrid
DataGrid Элемент управления позволяет выполнять проверку на уровне строк и ячеек. Когда пользователь обновляет значение проверки на уровне ячейки проверяются отдельные свойства объекта привязки данных. Когда пользователь вносит изменения в строку проверки на уровне строк проверяются целые объекты данных. Также можно реализовать визуальную реакцию на ошибки проверки или использовать визуальную обратную связь по умолчанию, DataGrid предоставляет элемент управления.
Следующие процедуры описывают способы применения правил проверки к DataGrid привязки и настраивать визуальную обратную связь.
Чтобы проверить значения отдельных ячеек
Укажите одно или несколько правил проверки для привязки, используемой со столбцом. Это аналогично проверке данных в простые элементы управления, как описано в разделе Общие сведения о привязке данных.
В следующем примере показан DataGrid элемента управления с четырьмя столбцами, которые привязаны к различным свойствам бизнес-объекта. Укажите трех столбцов ExceptionValidationRule , задав 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>
Когда пользователь вводит недопустимое значение (например, отличный от integer в столбце идентификатор курса), появится красная граница вокруг ячейки. Вы можете изменить эти отзывы проверки по умолчанию, как описано в следующей процедуре.
Настройка сигнала о проверке ячейки
Значение столбца EditingElementStyle свойство на стиль, соответствующий столбец редактирования элемента управления. Так как элементы управления создаются во время выполнения, нельзя использовать Validation.ErrorTemplate присоединенного свойства, как с помощью простых элементов управления.
В следующем примере обновляется предыдущего примера, добавив стиля ошибки, применяемое для трех столбцов с помощью правил проверки. Когда пользователь вводит недопустимое значение, стиль изменяет цвет фона ячейки и добавляет всплывающей подсказки. Обратите внимание на использование триггера, чтобы определить, имеется ли ошибка проверки. Это необходимо, поскольку в настоящее время отсутствует специальный шаблон ошибок для ячеек.
<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>
Можно реализовать дополнительную настройку, заменив CellStyle используемый столбцом.
Для проверки нескольких значений в одной строке
Реализуйте ValidationRule подкласса, который проверяет несколько свойств объекта привязки данных. В вашей Validate привести реализацию метода
value
значение параметра для BindingGroup экземпляра. Вы можете обращаться к объекту данных, используя Items свойство.В следующем примере демонстрируется этот процесс проверки ли
StartDate
значение свойства дляCourse
объекта более ранняя, чем его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; } } }
Добавить правило проверки к DataGrid.RowValidationRules коллекции. RowValidationRules Свойство обеспечивает прямой доступ к ValidationRules свойство BindingGroup экземпляр, который группирует все привязки, используемые элементом управления.
В следующем примере задается RowValidationRules свойства в XAML. ValidationStep Свойству UpdatedValue таким образом, чтобы проверка осуществляется только после обновления объект привязанных данных.
<DataGrid.RowValidationRules> <local:CourseValidationRule ValidationStep="UpdatedValue"/> </DataGrid.RowValidationRules>
Когда пользователь указывает дату окончания, более ранняя, чем дата начала, в заголовке строки появляется красный восклицательный знак (!). Вы можете изменить эти отзывы проверки по умолчанию, как описано в следующей процедуре.
Настройка сигнала о проверке строки
Задайте свойство DataGrid.RowValidationErrorTemplate. Это свойство позволяет настраивать сигнала о проверке строки для отдельных DataGrid элементов управления. Могут также влиять на несколько элементов управления с помощью неявный стиль строки для установки DataGridRow.ValidationErrorTemplate свойство.
В следующем примере заменяется сигнала о проверке строки по умолчанию с более заметный индикатор. Когда пользователь вводит недопустимое значение, красный круг с белым восклицательным знаком отображается в заголовке строки. Эта операция выполняется для ошибок проверки строк и ячеек. Сообщение об ошибке отображается во всплывающей подсказке.
<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>
Пример
Следующий пример приводится полная демонстрация проверки ячеек и строк. Course
Класс предоставляет образец данных объект, реализующий IEditableObject для поддержки транзакций. DataGrid Элемент управления взаимодействует с IEditableObject чтобы пользователи могли отменить изменения, нажав клавишу ESC.
Note
Если вы используете Visual Basic, в первой строке файла MainWindow.XAML, замените x:Class="DataGridValidation.MainWindow"
с x:Class="MainWindow"
.
Чтобы протестировать проверку, попробуйте сделайте следующее:
В столбце идентификатор курса введите значение отличный от integer.
В столбце даты окончания введите дату, более ранняя, чем дата начала.
Удаление значения в идентификатор курса, Дата начала или дата окончания.
Чтобы отменить недопустимое значение для ячейки, поместите курсор в ячейку и нажмите клавишу ESC.
Чтобы отменить изменения для всей строки, когда текущая ячейка находится в режиме редактирования, дважды нажмите клавишу ESC.
При возникновении ошибки проверки, наведите указатель мыши на индикатор в заголовке строки, чтобы просмотреть сообщение об ошибке.
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;
}
}
}
}
<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>