【问题标题】:WPF/XAML - DataTriggers to set ValidatesOnDataErrors = false/true when a radio button is checkedWPF/XAML - 选中单选按钮时设置 ValidatesOnDataErrors = false/true 的 DataTriggers
【发布时间】:2011-08-19 15:13:50
【问题描述】:

我正在开发一个使用 DataAnnotations 实现 MVVM 设计模式的应用程序。该应用程序是一个动态生成的页面列表。在其中一个页面上,我有 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
  • 我试过了,没用。问题是,一旦 ValidatesOnDataErrors 设置为 True 并且我尝试使用 ValidatesOnDataErrors = False 或不使用 ValidatesOnDataErrors 重新绑定它,或者即使我没有将它绑定到任何东西,它也不会删除验证。这是我的属性的样子: [Required(ErrorMessage = "Required Field!")] public string JobTitle { get { return _jobTitle; } 设置 { _jobTitle = 值; } } 谢谢,
  • 也许它没有更新 UI,因为 BindingSource 没有改变。尝试在 RadioButton 更改时在 ViewModel 中引发 PropertyChanged 事件,此外还要重新绑定属性。
  • 感谢您的快速回复,让我试试,稍后会回复。
  • 还是没有运气!它打开了估值,但没有关闭。顺便说一句,在我的单选按钮属性设置器中,我引发了 onpropertychanged 事件并传递了属性名称。我在每个属性设置器中都这样做。我在这里错过了什么吗?

标签: wpf xaml mvvm triggers


【解决方案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>

【讨论】:

  • 这不会在 UI 上显示错误,但是,页面仍然无效,这意味着我仍然无法触发 nextCommand,因为 JobTitle 属性需要进行字段验证。
  • 您不能更改您的IsValid 代码以仅检查基于RadioButton 检查的特定属性的验证吗?
  • 这就是我目前拥有的方式。在我的 ValidationViewModelBase 类中,我继承了 IDataErrorInfo 和 IValidationExceptionHandler。我通过基于传递的属性名称添加或删除字段验证来过滤“this”方法中的validationAttribute 列表。然而,这个应用程序有超过 500 个字段,所以验证基类目前看起来很丑。
  • @Bobby 我不确定我理解你的意思。你能发布一段简化的代码来展示你的IDataError 实现吗?
  • 我在下面发布了我的代码,如果您需要更多详细信息,请查看并告诉我。
【解决方案2】:
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 可以为我完成这项工作。如果您有不同的方法,请告诉我。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-23
  • 2017-10-25
  • 1970-01-01
  • 2014-08-08
相关资源
最近更新 更多