Wpf 使用IEditableObject的DataGrid验证行为
以下是当用户单击DataGrid中的最后一行以添加新项时所需的行为:Wpf 使用IEditableObject的DataGrid验证行为,wpf,validation,data-binding,datagrid,Wpf,Validation,Data Binding,Datagrid,以下是当用户单击DataGrid中的最后一行以添加新项时所需的行为: 显示新行的项目编号;即,如果列表中有N个项目,则项目编号为N+1 将光标放在“名称”列中,以便用户可以为项目命名 如果用户未输入名称,请通过 在行中显示eror图示符 Hilight名称DataGridCell 显示消息“需要名称”作为工具提示 如果我单独使用IDataErrorInfo,我会得到一些接近但不正确的结果:新行项目已经出错,而用户没有机会输入任何内容 因此,我尝试添加IEditableObject并使用布尔
- 在行中显示eror图示符
- Hilight名称DataGridCell
- 显示消息“需要名称”作为工具提示
贝里尔 杂货店项目代码 MainViewModel代码
公共可观察收集杂货店列表
{
获取{return\u groceryList;}
设置
{
_groceryList=价值;
RaisePropertyChangedEvent(“杂货店”);
}
}
私人可观察收集杂货店;
void OnGroceryListChanged(对象发送方,NotifyCollectionChangedEventArgs e){
...
//对列表重新排序
SequencingService.SetCollectionSequence(杂货店列表);
}
数据网格xaml
我最终确定了新条目名称的插入值,如下所示。现在,IEditableObject所要做的就是删除Cancel上的项 干杯,
贝里尔
#region Implementation of IDataErrorInfo
public string this[string columnName] {
get {
if(IsNewItem) return string.Empty;
if (columnName == "Name") {
if (string.IsNullOrEmpty(Name))
return "The name of the item to buy is required";
}
return string.Empty;
}
}
public string Error
{
get
{
var error = new StringBuilder();
// iterate over all of the properties
// of this object - aggregating any validation errors
var props = TypeDescriptor.GetProperties(this);
foreach (PropertyDescriptor prop in props)
{
var propertyError = this[prop.Name];
if (propertyError != string.Empty) {
var leadingString = (error.Length != 0 ? ", " : "");
error.Append(leadingString + propertyError);
}
}
return error.Length == 0 ? null : error.ToString();
}
}
private void NotifyErrorChanged() { RaisePropertyChangedEvent("Error"); }
#endregion
#region Implementation of IEditableObject
public bool IsNewItem { get; private set; }
public void BeginEdit() {
IsNewItem = true;
}
public void EndEdit() {
IsNewItem = false;
if(Error!=null)
NotifyErrorChanged();
}
public void CancelEdit() { IsNewItem = false; }
#endregion
public ObservableCollection<GroceryItem> GroceryList
{
get { return _groceryList; }
set
{
_groceryList = value;
RaisePropertyChangedEvent("GroceryList");
}
}
private ObservableCollection<GroceryItem> _groceryList;
void OnGroceryListChanged(object sender, NotifyCollectionChangedEventArgs e) {
...
// Resequence the list
SequencingService.SetCollectionSequence(GroceryList);
}
<Style x:Key="RowStyle" TargetType="{x:Type DataGridRow}">
<Setter Property="AllowDrop" Value="True" />
<Setter Property="ValidationErrorTemplate">
<Setter.Value>
<ControlTemplate>
<Grid>
<Ellipse Width="12" Height="12"
Fill="Red" Stroke="Black"
StrokeThickness="0.5"/>
<TextBlock FontWeight="Bold" Padding="4,0,0,0"
Margin="0" VerticalAlignment="Top" Foreground="White" Text="!"
ToolTip="{Binding RelativeSource={RelativeSource
FindAncestor, AncestorType={x:Type DataGridRow}},
Path=(Validation.Errors)[0].ErrorContent}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<DockPanel>
<DataGrid
x:Name="MainGrid" RowStyle="{StaticResource RowStyle}" CanUserAddRows="True"
ItemsSource="{Binding GroceryList}" SelectedItem="{Binding SelectedItem}"
AutoGenerateColumns="False"
...
>
<DataGrid.Columns>
<DataGridTextColumn Header="" Width="40" ElementStyle="{StaticResource NumberStyle}" Binding="{Binding SequenceNumber, Mode=OneWay}" IsReadOnly="True" />
<DataGridTextColumn Header="Item" Width="*" Binding="{Binding Name, ValidatesOnDataErrors=True}" IsReadOnly="False" />
</DataGrid.Columns>
</DataGrid>
</DockPanel>
#region Implementation of IEditableObject
public void BeginEdit() { }
public void EndEdit() { }
public void CancelEdit() {
Debug.Assert(GroceryList!=null);
GroceryList.Remove(this);
}
#endregion