验证规则却与验证规则正确更新(Validation Rule not updating correc

2019-07-20 06:11发布

我已经经历有关验证规则的一些帖子看了,但没有带碰到我遇到的问题。

我使用的是验证规则在WPF窗口一个文本框。 我有两个检查,一个空文本框,以及一个使用正则表达式匹配无效字符。

我的问题是这样的:

在我的文本框:

  1. A型 - 作品,显示空话
  2. 打退格为空字符串 - 作品,显示验证错误消息“请在所有字段中输入一个值”
  3. 类型! - 不工作 - 它应该显示“无效字符被发现”,但仍显示“请在所有字段中输入一个值。”
  4. Backspace键清空与字符串技术上的作品,因为它仍然显示第一个错误“请在所有字段中输入一个值。”
  5. A型 - 工程部,没有错误信息
  6. 类型! - 精细,显示信息“无效字符被发现。

同样的情况倒过来。

打开窗户

  1. 类型! - 精细,显示“无效字符被发现。
  2. Backspace键空字符串 - 仍显示“无效字符被发现”,而不是“请在所有字段中输入一个值。

我的代码如下:

ProviderNew.xaml:

<Label Name="lblProviderName" Content="Provider Name: " 
                   Grid.Row="1" Grid.Column="0"/>

<TextBox Name="txtBoxProviderName" Margin="2" 
    MaxLength="20" CharacterCasing="Upper"
    Grid.Row="1" Grid.Column="1" LostFocus="TxtBoxProviderNameLostFocus"   TextChanged="TxtBoxProviderNameTextChanged">
                <TextBox.Text>
                    <Binding ElementName="This" Path="ProviderName" UpdateSourceTrigger="PropertyChanged">
                        <Binding.ValidationRules>
                            <Domain:ProviderValidation />
                        </Binding.ValidationRules>
                    </Binding>
                </TextBox.Text>
            </TextBox>

            <TextBlock x:Name="tbNameValidation"  Foreground="Red" FontWeight="Bold" Margin="10,0,0,0"
                       Text="{Binding ElementName=txtBoxProviderName, Path=(Validation.Errors), Converter={StaticResource eToMConverter}}"
                       Grid.Row="1" Grid.Column="2" />

背后Privder码 - ProviderNew.xaml.cs

public static readonly DependencyProperty NewProviderNameProperty = DependencyProperty.Register("ProviderName",
        typeof (string), typeof(ProviderNew), new UIPropertyMetadata(""));


    public string ProviderName
    {
        get { return (string) GetValue(NewProviderNameProperty); }
        set { SetValue(NewProviderNameProperty, value); }
    }

值转换器类

public class ErrorsToMessageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var sb = new StringBuilder();
        var errors = value as ReadOnlyCollection<ValidationError>;

        if (errors != null && errors.Count > 0)
        {

            foreach (var e in errors.Where(e => e.ErrorContent != null))
            {
                sb.AppendLine(e.ErrorContent.ToString());
            }
        }
        return sb.ToString();
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Provider类

private string _providerName;
    public string ProviderName
    {
        get { return _providerName; }
        set
        {
            _providerName = value;
            RaisePropertyChanged("ProviderName");
        }
    }

private void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = this.PropertyChanged;

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

验证规则类

public class ProviderValidation : ValidationRule
{
    public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
    {
        var str = value as string;

        if (str != null && !Regex.IsMatch(str, @"^[a-zA-Z0-9]*$"))
        {
           return new ValidationResult(false, "Invalid characters were found.");
        }


        if (String.IsNullOrEmpty(str))
        {
            return new ValidationResult(false, "Please enter a value in all fields.");
        }

        return new ValidationResult(true, null);
    }
}

我曾尝试是同时设置引发LostFocus和框TextChanged事件的使用给力更新:

var expression = txtBoxProviderName.GetBindingExpression(TextBox.TextProperty);
if (expression != null)
    expression.UpdateSource();

在验证方法设置断点表明,正确的匹配完成并返回正确的ValidationResult,但它不能正常更新文本。

我做得令人难以置信的愚蠢?

任何建议将不胜感激。

编辑1。

是啊,我有工作,使用MultiDataTrigger并绑定到文本框。

什么不工作是当我第一次显示窗口,按钮被启用,这是我不希望它是,因为这可以让用户点击保存空文本框。

验证规则不直接从一开始的窗口打开时工作。

我设置文本框的焦点,如果它失去焦点或不正确的数据输入,然后验证规则踢和禁用按钮。

设置按钮默认禁用,使得它在打开禁用,但是当没有验证错误,它没有实现。

我可以把它通过强制验证规则的检查工作,对说Load事件,使用

var expression = txtBoxProviderName.GetBindingExpression(TextBox.TextProperty);
if (expression != null)
    expression.UpdateSource();

但随后的窗口第一次打开时,它会立即显示验证错误消息,我真的不喜欢的样子“请在所有字段中输入一个值”。

任何办法解决这,或者我没有两全其美。

这里是按钮的代码

<Button x:Name="btnSave" Height="25" Width="100" Content="Save" HorizontalAlignment="Right" Margin="0,0,120,0"
            Grid.Row="2" Click="BtnSaveClick" >
        <Button.Style>
            <Style TargetType="{x:Type Button}">
                <Setter Property="IsEnabled" Value="False" />
                <Style.Triggers>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding ElementName=txtBoxProviderName, Path=(Validation.HasError)}" Value="False" />
                            <Condition Binding="{Binding ElementName=txtBoxHelpDesk, Path=(Validation.HasError)}" Value="False" />
                            <Condition Binding="{Binding ElementName=txtBoxRechargeInstructions, Path=(Validation.HasError)}" Value="False" />
                        </MultiDataTrigger.Conditions>
                        <Setter Property="IsEnabled" Value="True" />
                    </MultiDataTrigger>
                </Style.Triggers>
            </Style>
        </Button.Style>     
    </Button>

谢谢,

奥尼尔

编辑2

一个快速的问题。 我找不到RelayCommand命名空间。 搜索其他代码周围,我发现从微软的MVVM的例子,实现RelayCommand:ICommand的类。

它是否正确?

该代码是:

public class RelayCommand : ICommand
{
    #region Fields

    readonly Action<object> _execute;
    readonly Predicate<object> _canExecute;

    #endregion // Fields

    #region Constructors

    /// <summary>
    /// Creates a new command that can always execute.
    /// </summary>
    /// <param name="execute">The execution logic.</param>
    public RelayCommand(Action<object> execute)
        : this(execute, null)
    {
    }

    /// <summary>
    /// Creates a new command.
    /// </summary>
    /// <param name="execute">The execution logic.</param>
    /// <param name="canExecute">The execution status logic.</param>
    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");

        _execute = execute;
        _canExecute = canExecute;
    }

    #endregion // Constructors

    #region ICommand Members

    [DebuggerStepThrough]
    public bool CanExecute(object parameter)
    {
        return _canExecute == null ? true : _canExecute(parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }

    #endregion // ICommand Members
}

我实现我的ProviderNew.xaml.cs如下:

private ICommand saveCommand;
    public ICommand SaveCommand
    {
        get
        {
            if (saveCommand == null)
            {
                saveCommand = new RelayCommand(p => DoSave(), p => CanSave() );
            }
            return saveCommand;
        }
    }

    private bool CanSave()
    {
        if (!string.IsNullOrEmpty(ProviderName))
        {
            ??? What goes here? 
        }


        return true;
    }
private bool DoSave()
    {
        // Save the information to DB
    }

说实话,我不确定我应该在挡在了“如果(!string.IsNullOrEmpty(的ProviderName))”进行编码

另外你说要加在的DataContext ICommand的代码,所以不知道这是否是在正确的地方,因为当我打开窗户,保存为启用并单击它什么都不做,即使所有的领域有它的正确性。

下面是按钮的ProviderNew XAML代码

<Button x:Name="btnSave" Height="25" Width="100" Content="Save" HorizontalAlignment="Right" Margin="0,0,120,0"
            Grid.Row="2" Command="{Binding SaveCommand}" >
        <Button.Style>
            <Style TargetType="{x:Type Button}">
                <Setter Property="IsEnabled" Value="False" />
                <Style.Triggers>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding ElementName=txtBoxHelpDesk, Path=(Validation.HasError)}" Value="False" />
                            <Condition Binding="{Binding ElementName=txtBoxProviderName, Path=(Validation.HasError)}" Value="False" />
                            <Condition Binding="{Binding ElementName=txtBoxRechargeInstructions, Path=(Validation.HasError)}" Value="False" />
                        </MultiDataTrigger.Conditions>
                        <Setter Property="IsEnabled" Value="True" />
                    </MultiDataTrigger>
                </Style.Triggers>
            </Style>
        </Button.Style>     
    </Button>

非常感激您的帮忙。

问候,

奥尼尔

Answer 1:

好吧,我设法重现此问题,这是窃听我,这是行不通的。 但我想通了。
问题是,当误差的变化,因为实际的财产(的ProviderName)不因有效性规则改变转换器没有被解雇。 如果你把一个断点在转换器中,有效性规则和物业制定者可以看到此行为。

因此,而不是使用IValueConverter ,你应该改变的结合tbNameValidation以下几点:

<TextBlock x:Name="tbNameValidation"  
           Text="{Binding ElementName=txtBoxProviderName, 
                  Path=(Validation.Errors).CurrentItem.ErrorContent}">

的重要部分是Path=(Validation.Errors).CurrentItem.ErrorContent" 。这将确保所显示的当前的错误信息。

另外,如果你想在“ 请在所有字段中输入一个值 ”的消息从一开始就表明,你应该添加Mode=TwoWay ,以结合txtBoxProviderName

 <Binding ElementName="This" 
          Path="ProviderName" 
          UpdateSourceTrigger="PropertyChanged"
          Mode="TwoWay">

编辑第2部分

修复按钮的enabled属性,你可以为你在你的问题,但不是使用使用相同的代码Click事件来运行你保存代码,你可以使用Command属性来代替:

在您的DataContext,创建类型的属性ICommand ,按钮绑定到这一点:

<Button Command="{Binding SaveCommand}" .... />

private ICommand saveCommand; 
public ICommand SaveCommand { 
    get { 
        if (saveCommand == null) {
            saveCommand = new RelayCommand(p => DoSave(), p=> CanSave() ); 
         } 
         return saveCommand; 
      } 
 }

和CanSave实现可以检查是否所有期望得到满足:

private bool CanSave(){
   if (!string.IsNullOrEmpty(ProviderName)){
       //.... etc
   }
 }

所述CanSave()将决定你按钮的状态,这是因为会的CommandBinding自动采取根据使能按钮的护理CanExecute有界命令的方法。 您验证的逻辑将回到这里来的,所以它可能是找到一种方法来利用这些代码是个好主意。

有关更多信息中继命令



文章来源: Validation Rule not updating correctly with 2 validation rules