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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30216321/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 13:07:52  来源:igfitidea点击:

WPF- validation error event doesn't fire

c#wpfvalidationeventserror-handling

提问by DasDas

i think i have read already all related articles but non of them help..

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

im trying to enable/disable a save button of datagridby the error state- but with no success.

我试图启用/禁用datagrid错误状态的保存按钮 -但没有成功。

this is my code:

这是我的代码:

contractor:

承包商:

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

XAML:

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>

code behind:

后面的代码:

    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;
    }

but the "OnErrorEvent"never fires- any idea why?

但是"OnErrorEvent"从不着火-知道为什么吗?

采纳答案by hbarck

The attribute

属性

Validation.Error="Michlolim_Managment_Error"

in your XAML already sets a handler for the error event on the window level, however, to a method which isn't defined in your code behind fragment. Your AddHandler call looks ok, but, depending on where it is in the constructor, it might get overridden by the XAML event handler definition.

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

Probably not related, but you might want to change

可能不相关,但你可能想要改变

(Validation.Errors)[0].ErrorContent

to

(Validation.Errors)/ErrorContent

in your ToolTip bindings, since the former causes binding errors if there are no errors. Unfortunately, it is still contained in the documentation samples...

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

回答by Bijington

Try creating a class like the following:

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

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
}

This will provide an error whenever there is a change to the Name property. Please note that if you wish to trigger new validation checks without modifying the property you just need to call:

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

  RaisePropertyChanged(x => x.Name);

You will then need to change your binding to something like:

然后,您需要将绑定更改为:

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

Note you will have to load your data from the DB and create a descriptor for each item you want to display in the DataGrid.

请注意,您必须从数据库加载数据并为要在 DataGrid 中显示的每个项目创建一个描述符。

The reason behind why you aren't seeing the event being fired:

您没有看到事件被触发的原因:

You aren't raising property change events (INotifyPropertyChanged or through a DependencyProperty) therefore the UI won't receive updates and the event won't be fired because it hasn't received an update to then perform the validation. By binding direct to your DB then you aren't raising the property change events. You can see that the Name property I suggested in my answer does raise the property changed event

您不会引发属性更改事件(INotifyPropertyChanged 或通过 DependencyProperty),因此 UI 不会收到更新,也不会触发该事件,因为它尚未收到更新以执行验证。通过直接绑定到您的数据库,您就不会引发属性更改事件。您可以看到我在回答中建议的 Name 属性确实引发了属性更改事件

回答by kmcnamee

From my sample of your code I think you are missing specifying UpdateSourceTrigger="PropertyChanged" or UpdateSourceTrigger="LostFocus" on the DataGridTextColumn in the DataGrid instead of using the default behavior of the DataGrids binding.

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

That is assuming my assumptions are correct see bottom.

那是假设我的假设是正确的,见底部。

Your code causes OnErrorEvent to fire if i change:

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

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

To include UpdateSourceTrigger for PropertyChanged or LostFocus like so:

要为 PropertyChanged 或 LostFocus 包含 UpdateSourceTrigger,如下所示:

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

enter image description here

在此处输入图片说明

Assumptions - For your ValidationRule to test i made it always return false (see below). And for the test item source i am binding to a string value in 'agaf_name' property.

假设 - 为了您的 ValidationRule 进行测试,我让它总是返回 false(见下文)。对于测试项目源,我将绑定到“agaf_name”属性中的字符串值。

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

回答by Adi Lester

You need to set NotifyOnValidationError="True"on your bindings - otherwise, the event won't be raised. I would recommend using the IDataErrorInfoor INotifyDataErrorInfointerfaces instead for an MVVM error handling approach.

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