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

时间:2015-05-13 13:28:19

标签: c# wpf validation events error-handling

我想我已经读过所有相关文章,但没有帮助..

我尝试按错误状态启用/禁用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"永远不会发生任何想法?

4 个答案:

答案 0 :(得分: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将不会接收更新,并且不会触发事件,因为它尚未收到更新然后执行验证。通过直接绑定到您的数据库,您不会提出属性更改事件。您可以看到我在答案中建议的Name属性确实引发了属性更改事件

答案 1 :(得分:2)

您需要在绑定上设置NotifyOnValidationError="True" - 否则,该事件不会被提升。我建议使用mysqli_error($conn); IDataErrorInfo接口代替MVVM错误处理方法。

答案 2 :(得分:2)

属性

Validation.Error="Michlolim_Managment_Error"
在您的XAML中,

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

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

(Validation.Errors)[0].ErrorContent

(Validation.Errors)/ErrorContent

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

答案 3 :(得分:2)

从我的代码示例中,我认为您缺少在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" >
   ....

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