WPF / XAML - 当单选按钮被选中时,使用DataTriggers设置ValidatesOnDataErrors = false / true

3
我正在开发一个实现MVVM设计模式和DataAnnotations的应用程序。该应用程序是一个动态生成的页面列表。在这些页面中的一个页面上,我有10个必填字段和2个是/否单选按钮。这10个字段被分为两组,并且每个组都用边框标签包装起来。每个边框的可见性都与隐藏/可见的单选按钮绑定。

我的问题是如果选择了“是”,并显示了相关的5个必填文本框,如何将ValidatesOnDataErrors设置为false/true,并清除其他隐藏的必填文本框的文本框值?

下面是一段代码片段。
谢谢
<Border>
<Border.Style>
  <Style>
   <Setter Property="Border.Visibility" Value="Hidden"></Setter>
    <Style.Triggers>
     <DataTrigger Binding="{Binding ElementName=PresentlyEmployed_yes, Path=IsChecked}"
                  Value="True">
       <Setter Property="Border.Visibility" Value="Visible"></Setter>
     </DataTrigger>
    </Style.Triggers>
   </Style>
  </Border.Style>
  <Grid Height="Auto" Width="Auto">
   <Label Name="JobTitle"
               Content="{x:Static properties:Resources.JobTitlelbl}" />
    <TextBox Name="JobTitle" Text="{Binding JobTitle, Mode=TwoWay, 
     ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}">
     <TextBox.Style>
      <Style TargetType="{x:Type TextBox}">
       <Setter Property="Text" Value="{Binding PrimaryInsuredBusinessDuties, Mode=TwoWay,
          UpdateSourceTrigger=PropertyChanged, IsAsync=True}" />
       <Style.Triggers>
       <DataTrigger Binding="{Binding ElementName=PresentlyEmployed_yes, Path=IsChecked}"
          Value="True">
        <Setter Property="Text" Value="{Binding JobTitle, Mode=TwoWay, 
           ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" />
       </DataTrigger>
       <DataTrigger Binding="{Binding ElementName=PresentlyEmployed_yes, Path=IsChecked}"
         Value="False">
        <Setter Property="Text" Value="{Binding JobTitle, Mode=TwoWay, 
          ValidatesOnDataErrors=False, UpdateSourceTrigger=PropertyChanged}"></Setter>
       </DataTrigger>
      </Style.Triggers>
     </Style>
    </TextBox.Style>
   </TextBox>
  </Grid>
</Border>

为什么不在触发器中重新绑定“Text”值,而不使用“ValidatesOnDataErrors”? - Rachel
我尝试过了,但没起作用。问题在于一旦将ValidatesOnDataErrors设置为True,我尝试使用ValidatesOnDataErrors = False进行重新绑定,或者不包括ValidatesOnDataErrors,甚至如果我不将其绑定到任何内容,都无法删除验证。以下是我的属性外观:[Required(ErrorMessage = "必填字段!")] public string JobTitle { get { return _jobTitle; } set { _jobTitle = value; } }谢谢。 - Bobby
也许它没有更新UI是因为BindingSource没有改变。尝试在ViewModel中当RadioButton改变时触发PropertyChanged事件,除了重新绑定属性。 - Rachel
谢谢您的快速回复,让我试一下,稍后会再联系您。 - Bobby
还是没有运气!它把验证开启了,但却无法关闭。顺便说一下,在我的单选按钮属性设置器中,我会引发onpropertychanged事件并传递属性名称。我在每个属性设置器中都这样做。我有什么遗漏的吗? - Bobby
2个回答

1

如果不想显示验证错误,可以尝试将Validation.Template设为{x:Null}

<StackPanel>
    <ListBox x:Name="MyListBox" SelectedIndex="0">
        <ListBoxItem>Validate Value 1</ListBoxItem>
        <ListBoxItem>Validate Value 2</ListBoxItem>
    </ListBox>

    <TextBox Text="{Binding Value1, ValidatesOnDataErrors=True}">
        <TextBox.Style>
            <Style TargetType="{x:Type TextBox}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding SelectedIndex, ElementName=MyListBox}" Value="1" >
                        <Setter Property="Validation.ErrorTemplate" Value="{x:Null}" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TextBox.Style>
    </TextBox>
    <TextBox Text="{Binding Value2, ValidatesOnDataErrors=True}">
        <TextBox.Style>
            <Style TargetType="{x:Type TextBox}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding SelectedIndex, ElementName=MyListBox}" Value="0" >
                        <Setter Property="Validation.ErrorTemplate" Value="{x:Null}" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TextBox.Style>
    </TextBox>
</StackPanel>

这并不会在用户界面上显示错误,但页面仍然无效,这意味着由于JobTitle属性的必填字段验证,我仍然无法触发nextCommand。 - Bobby
你能否修改你的 IsValid 代码,根据选中的 RadioButton 来仅检查特定属性的验证? - Rachel
这就是我目前的情况。在我的ValidationViewModelBase类中,我继承了IDataErrorInfo和IValidationExceptionHandler。我通过在“this”方法中添加或删除字段验证来过滤validationAttribute列表,具体取决于传递的属性名称。然而,这个应用程序有超过500个字段,所以验证基类目前看起来很丑陋。 - Bobby
@Bobby,我不确定我理解你的意思。你能发一小段简化的代码展示你的“IDataError”实现吗? - Rachel
我在下面发布了我的代码,请看一下并告诉我是否需要更多细节。 - Bobby

0
Sure, here is how my validationbase class looks like (Simplified)

    public class ValidationViewModelBase : ViewModelBase, IDataErrorInfo,   IValidationExceptionHandler
    {
    private Dictionary<string, Func<ValidationViewModelBase, object>> _propertyGetters;
    private Dictionary<string, ValidationAttribute[]> _validators;

    /// <summary>
    /// Gets the error message for the property with the given name.
    /// </summary>
    /// <param name="propertyName">Name of the property</param>
    public string this[string propertyName]
    {
         IList<string> fieldsNames = new List<string>();
    {
    if (propertyName == "PresentlyEmployed")
      {
        //if its true then
        fieldsNames.Add("JobTitle");

        AddFieldsValidation(fieldsNames); 
        }else{

        fieldsNames.Add("EmploymentAddress");

        RemoveValidation(fieldsNames); 
    }

  if (this.propertyGetters.ContainsKey(propertyName))
      {
            var propertyValue = this.propertyGetters[propertyName](this);
        var errorMessages = this.validators[propertyName]
                        .Where(v => !v.IsValid(propertyValue))
                        .Select(v => v.ErrorMessage).ToArray();
        return string.Join(Environment.NewLine, errorMessages);
      }
    return string.Empty;
    }

    /// <summary>
    /// Gets an error message indicating what is wrong with this object.
    /// </summary>
    public string Error
    {
        get
        {
        var errors = from validator in this.validators
                        from attribute in validator.Value
            where !attribute.IsValid(this.propertyGetters[validator.Key](this))
            select attribute.ErrorMessage;

            return string.Join(Environment.NewLine, errors.ToArray());
            }
        }

    }

    /// <summary>
    /// Gets the number of properties which have a validation attribute and are  currently valid
    /// </summary>
    public int ValidPropertiesCount
    {
        get
        {
            var query = from validator in this.validators
                where validator.Value.All(attribute => attribute.IsValid(this.propertyGetters[validator.Key](this)))
                select validator;

            var count = query.Count() - this.validationExceptionCount;
            return count;
            }
        }
}

/// <summary>
    /// Gets the number of properties which have a validation attribute
    /// </summary>
    public int TotalPropertiesWithValidationCount
    {
        get
        {
            return this.validators.Count();
        }
    }

public ValidationViewModelBase()
    {
        this.validators = this.GetType()
            .GetProperties()
            .Where(p => this.GetValidations(p).Length != 0)
            .ToDictionary(p => p.Name, p => this.GetValidations(p));

        this.propertyGetters = this.GetType()
            .GetProperties()
            .Where(p => this.GetValidations(p).Length != 0)
            .ToDictionary(p => p.Name, p => this.GetValueGetter(p));
    }

private ValidationAttribute[] GetValidations(PropertyInfo property)
    {
        return (ValidationAttribute[])property.GetCustomAttributes(typeof(ValidationAttribute), true);
    }

    private Func<ValidationViewModelBase, object> GetValueGetter(PropertyInfo property)
    {
        return new Func<ValidationViewModelBase, object>(viewmodel => property.GetValue(viewmodel, null));
    }

    private int validationExceptionCount;

    public void ValidationExceptionsChanged(int count)
    {
        this.validationExceptionCount = count;
        this.OnPropertyChanged("ValidPropertiesCount");
    }

@Rachel:上面的代码目前正在发挥作用。但是,我对添加或删除字段的方式并不感到自豪。因此,我想也许可以使用DataTriggers来完成这项工作。如果你有不同的方法,请告诉我。谢谢 - Bobby

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接