WPF - 验证错误事件未触发

10

我认为我已经阅读了所有相关文章,但是没有任何一篇对我有帮助。

我正在尝试根据错误状态启用/禁用datagrid的保存按钮,但是一直没有成功。

这是我的代码:

contractor:

AddHandler(Validation.ErrorEvent, new RoutedEventHandler(OnErrorEvent));

XAML:

    <Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
  xmlns:col="clr-namespace:System.Collections;assembly=mscorlib"
 xmlns:local="clr-namespace:Metsuka_APP" x:Class="Metsuka_APP.MichlolimManagment" 
  mc:Ignorable="d" 
  d:DesignHeight="500" d:DesignWidth="500"
Title="MichlolimManagment"
x:Name="Michlolim_Managment" Validation.Error="Michlolim_Managment_Error">
<Page.Resources>

<DataGrid x:Name="AGAFIMDataGrid" VerticalAlignment="Center" RowEditEnding="rowEditEnding" Margin="10" FlowDirection="RightToLeft" Height="340"
    AutoGenerateColumns="False" EnableRowVirtualization="True"
                  ItemsSource="{Binding Source={StaticResource aGAFIMViewSource}}"   Grid.Row="1"
                  RowDetailsVisibilityMode="VisibleWhenSelected"
                 ScrollViewer.CanContentScroll="True"
                 ScrollViewer.VerticalScrollBarVisibility="Auto" 
                 HorizontalGridLinesBrush="Silver"
                 VerticalGridLinesBrush="Silver">
            <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 x:Name="agaf_nameColumn"  Header="name" Width="*">
                    <DataGridTextColumn.Binding>
                        <Binding Path="agaf_name" NotifyOnValidationError="True" >
                            <Binding.ValidationRules>
                            <local:MichlolimValidationRule ValidationStep="UpdatedValue"/>
                        </Binding.ValidationRules>
                    </Binding>
                        </DataGridTextColumn.Binding>
                </DataGridTextColumn>
            </DataGrid.Columns>
            <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>

后台代码:

    private int errorCount;

    private void OnErrorEvent(object sender, RoutedEventArgs e)
    {
        var validationEventArgs = e as ValidationErrorEventArgs;
        if (validationEventArgs == null)
            throw new Exception("Unexpected event args");
        switch (validationEventArgs.Action)
        {
            case ValidationErrorEventAction.Added:
                {
                    errorCount++; break;
                }
            case ValidationErrorEventAction.Removed:
                {
                    errorCount--; break;
                }
            default:
                {
                    throw new Exception("Unknown action");
                }
        }
        btnSavePop.IsEnabled = errorCount == 0;
    }

但是"OnErrorEvent"从未触发-有任何想法为什么?


你能发布一下在DataGrid中显示的模型的代码吗?主要是agaf_name属性。 - Bijington
它是基于数据库的 - 你想看到什么代码? - DasDas
我想要查看属性的定义,以了解绑定是如何起作用的。正如 Adi 在答案中提到的那样,您需要实现 IDataErrorInfo 接口,并且还需要将其绑定到一个依赖属性上,或者在被绑定的类上使用 INotifyPropertyChanged。 - Bijington
4个回答

4

您需要在绑定上设置 NotifyOnValidationError="True" - 否则,事件不会被触发。我建议使用 IDataErrorInfoINotifyDataErrorInfo 接口,以便采用 MVVM 错误处理方法。


3

尝试创建一个类,如下所示:

public class AgafDescriptor : INotifyPropertyChanged, IDataErrorInfo
{
    private string _name;

    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            if (_name != value)
            {
                _name = value;

                RaisePropertyChanged(x => x.Name);
            }
        }
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged<T>(Expression<Func<AgafDescriptor, T>> propertyExpression)
    {
        PropertyChangedEventHandler localPropertyChanged = this.PropertyChanged as PropertyChangedEventHandler;

        if ((localPropertyChanged != null) && (propertyExpression != null))
        {
            MemberExpression body = propertyExpression.Body as MemberExpression;

            if (body != null)
            {
                localPropertyChanged(this, new PropertyChangedEventArgs(body.Member.Name));
            }
        }
    }

    #endregion

    #region IDataErrorInfo Members

    // Does nothing in WPF.
    public string Error
    {
        get { return null; }
    }

    public string this[string columnName]
    {
        get
        {
            string returnVal = null;

            if (string.Equals("Name", columnName, StringComparison.Ordinal))
            {
                if (string.IsNullOrWhiteSpace(Name))
                {
                    returnVal = "A name must be supplied.";
                }
            }

            return returnVal;
        }
    }

    #endregion
}

每当Name属性发生变化时,就会出现错误。请注意,如果您希望在不修改属性的情况下触发新的验证检查,只需调用:

  RaisePropertyChanged(x => x.Name);

然后您需要将绑定更改为类似以下内容:

<DataGridTextColumn x:Name="agaf_nameColumn"  Header="name" Width="*" Binding="{Binding Name, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, NotifyOnValidationError=True}"/>

请注意,您需要从数据库中加载数据并为要在DataGrid中显示的每个项目创建描述符。
您看不到事件被触发的原因是:您没有引发属性更改事件(通过INotifyPropertyChanged或DependencyProperty),因此UI不会收到更新,事件不会被触发,因为它没有接收到更新,以便进行验证。如果直接绑定到DB,则不会引发属性更改事件。您可以看到我在答案中建议的Name属性确实引发了属性更改事件。

我需要为每个需要检查的列创建这样一个类吗? - DasDas
不,你应该为每个要检查的列拥有一个属性。 - Bijington
但是,这仍然没有回答我的问题,为什么事件没有被触发 :( - DasDas
如果您没有引发属性更改事件(通过INotifyPropertyChanged或DependencyProperty),则UI将不会接收更新,因此事件不会被触发,因为它还没有接收到更新以执行验证。通过直接绑定到数据库,您不会引发属性更改事件。您可以看到我在答案中建议的Name属性确实引发了属性更改事件。 - Bijington

2

根据我对您的代码样本的了解,我认为您遗漏了在DataGridTextColumn中指定UpdateSourceTrigger="PropertyChanged"或UpdateSourceTrigger="LostFocus",而是使用DataGrid的默认绑定行为。假设我的假设是正确的,请按照下面的说明进行操作。

如果我更改您的代码,则会导致OnErrorEvent触发:

<DataGridTextColumn.Binding>
  <Binding Path="agaf_name" NotifyOnValidationError="True"  >
  ...

要像下面这样包含 PropertyChanged 或 LostFocus 的 UpdateSourceTrigger:

<DataGridTextColumn.Binding>
   <Binding Path="agaf_name" NotifyOnValidationError="True" UpdateSourceTrigger="PropertyChanged" >
   ....

enter image description here

假设 - 为了测试您的ValidationRule,我使其始终返回false(如下所示)。 对于测试项来源,我将绑定到'agaf_name'属性中的字符串值。

public class MichlolimValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
    {
        return new ValidationResult(false, "bad");
    }
}

2
属性
该属性
Validation.Error="Michlolim_Managment_Error"

您的XAML已经在窗口级别设置了错误事件的处理程序,但是它指向的方法没有在代码后台片段中定义。您的AddHandler调用看起来没问题,但是根据它在构造函数中的位置,可能会被XAML事件处理程序定义覆盖。

可能与此无关,但您可能想要更改

(Validation.Errors)[0].ErrorContent

to

(Validation.Errors)/ErrorContent

在您的工具提示绑定中,应使用 "DataErrors" 而不是 "Errors",因为如果没有错误,前者会导致绑定错误。不幸的是,它仍然包含在文档示例中...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接