WPF- 验证错误事件不会触发

WPF- validation error event doesn't fire

我想我已经阅读了所有相关文章,但没有一篇有帮助..

我正在尝试 enable/disable 按错误状态 datagrid 的保存按钮 - 但没有成功。

这是我的代码:

承包商:

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" 永远不会触发 - 知道为什么吗?

您需要在绑定上设置 NotifyOnValidationError="True" - 否则,将不会引发该事件。我建议使用 IDataErrorInfoINotifyDataErrorInfo 接口来代替 MVVM 错误处理方法。

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

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
}

每当更改名称 属性 时,这将提供一个错误。请注意,如果您希望在不修改 属性 的情况下触发新的验证检查,您只需调用:

  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 不会收到更新并且不会触发该事件,因为它尚未收到更新以执行验证。通过直接绑定到您的数据库,您不会引发 属性 更改事件。您可以看到我在回答中建议的名称 属性 确实引发了 属性 changed 事件

属性

Validation.Error="Michlolim_Managment_Error"

在您的 XAML 中已经为 window 级别的错误事件设置了一个处理程序,但是,该处理程序未在您的代码隐藏片段中定义。您的 AddHandler 调用看起来没问题,但是,根据它在构造函数中的位置,它可能会被 XAML 事件处理程序定义覆盖。

可能不相关,但您可能想要更改

(Validation.Errors)[0].ErrorContent

(Validation.Errors)/ErrorContent

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

根据我的代码示例,我认为您没有在 DataGrid 中的 DataGridTextColumn 上指定 UpdateSourceTrigger="PropertyChanged" 或 UpdateSourceTrigger="LostFocus" 而不是使用 DataGrids 绑定的默认行为。

这是假设我的假设是正确的见底部。

如果我更改:

,您的代码会导致 OnErrorEvent 触发
<DataGridTextColumn.Binding>
  <Binding Path="agaf_name" NotifyOnValidationError="True"  >
  ...

像这样为 PropertyChanged 或 LostFocus 包含 UpdateSourceTrigger:

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

假设 - 为了让您的 ValidationRule 进行测试,我始终将其设置为 return false(见下文)。对于测试项目源,我绑定到 'agaf_name' 属性.

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