【问题标题】:WPF- validation error event doesn't fireWPF-验证错误事件不会触发
【发布时间】:2015-07-24 19:54:05
【问题描述】:

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

我试图通过错误状态启用/禁用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" 永远不会触发 - 知道为什么吗?

【问题讨论】:

  • 您能否发布您在 DataGrid 中显示的模型的代码?主要是agaf_name 属性。
  • 它的数据库是基于你想看什么代码?
  • 我想看看属性是如何定义的,看看绑定是如何工作的。正如 Adi 刚刚在回答中建议的那样,您需要实现 IDataErrorInfo 但您还需要绑定到依赖属性或在绑定到的类上使用 INotifyPropertyChanged

标签: c# wpf validation events error-handling


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

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

    属性

    Validation.Error="Michlolim_Managment_Error"
    

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

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

    (Validation.Errors)[0].ErrorContent
    

    (Validation.Errors)/ErrorContent
    

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

    【讨论】:

      【解决方案4】:

      从我的代码示例中,我认为您缺少在 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,我让它始终返回 false(见下文)。对于测试项目源,我将绑定到“agaf_name”属性中的字符串值。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-23
        相关资源
        最近更新 更多