Wpf 使用IEditableObject的DataGrid验证行为

Wpf 使用IEditableObject的DataGrid验证行为,wpf,validation,data-binding,datagrid,Wpf,Validation,Data Binding,Datagrid,以下是当用户单击DataGrid中的最后一行以添加新项时所需的行为: 显示新行的项目编号;即,如果列表中有N个项目,则项目编号为N+1 将光标放在“名称”列中,以便用户可以为项目命名 如果用户未输入名称,请通过 在行中显示eror图示符 Hilight名称DataGridCell 显示消息“需要名称”作为工具提示 如果我单独使用IDataErrorInfo,我会得到一些接近但不正确的结果:新行项目已经出错,而用户没有机会输入任何内容 因此,我尝试添加IEditableObject并使用布尔

以下是当用户单击DataGrid中的最后一行以添加新项时所需的行为:

  • 显示新行的项目编号;即,如果列表中有N个项目,则项目编号为N+1
  • 将光标放在“名称”列中,以便用户可以为项目命名
  • 如果用户未输入名称,请通过
    • 在行中显示eror图示符
    • Hilight名称DataGridCell
    • 显示消息“需要名称”作为工具提示
  • 如果我单独使用IDataErrorInfo,我会得到一些接近但不正确的结果:新行项目已经出错,而用户没有机会输入任何内容

    因此,我尝试添加IEditableObject并使用布尔IsItemNew标志。但是使用下面的代码根本不会出现错误

    如何修复代码以获得所需的行为

    干杯,
    贝里尔

    杂货店项目代码 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