2017-01-16 25 views
1

ItemsControl内の項目の検証結果に応じてボタンの有効状態を設定しようとしています(検証エラーが発生した場合、存在する)。WPF ItemsControlの検証項目に基づく有効/無効ボタン

私はそうのような他の入力フィールドに成功し、これをやった:

<Style x:Key="SaveButtonStyle" TargetType="Button"> 
     <Style.Triggers> 
      <DataTrigger Binding="{Binding ElementName=MinValueTextBox, Path=(Validation.HasError)}" Value="True"> 
        <Setter Property="IsEnabled" Value="False"/> 
       </DataTrigger> 
     </Style.Triggers> 
    </Style> 

は、しかし、今私も同じように検証したいコレクションにバインドされたのItemsControlを持っています。 コレクションオブジェクトはIDataErrorInfoを実装します。

ボタンスタイルのDataTriggerでElementNameを指定できないため、私はこれをどうしますか?

すべてのコレクション項目のすべての入力フィールドが有効でない場合は、保存ボタンを無効にします。ここで

はDataTemplateを持つのItemsControlコードです:

<ItemsControl ItemsSource="{Binding FeedTypes}" ItemTemplate="{StaticResource FeedTypeDataTemplate}"/> 

<DataTemplate x:Key="FeedTypeDataTemplate"> 
    <Grid> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="*"/> 
      <ColumnDefinition Width="3*"/> 
      <ColumnDefinition Width="*"/> 
      <ColumnDefinition Width="3*"/> 
     </Grid.ColumnDefinitions> 

     <Label Content="{x:Static p:Resources.FeedTypeNameLabel}"/> 

     <TextBox Name="FeedTypeNameTxtBox" Text="{Binding UpdateSourceTrigger=PropertyChanged, Path=Name, 
      ValidatesOnDataErrors=true, NotifyOnValidationError=true}" Grid.Column="1"/> 

     <Label Content="{x:Static p:Resources.KgPerLitreLabel}" Grid.Column="2"/> 

     <TextBox x:Name="FeedTypeKgPerLitreTxtBox" Text="{Binding UpdateSourceTrigger=PropertyChanged, Path=KgPerLitre, 
      ValidatesOnDataErrors=true, NotifyOnValidationError=true}" Grid.Column="3"/> 
    </Grid> 
</DataTemplate> 

よろしく!

答えて

2

属性ベースの検証を使用してViewModelに検証をプッシュし、ボタンのCommandCanExecuteメソッド実装の一部として検証ステータスを確認します。

これは、検証目的で属性を使用してUI編集可能なプロパティにマークを付けるだけの柔軟性を提供し、すべてのViewModelプロパティ(ネストされたコレクションベースのアイテムを含む)が有効であることを確認するための単純なインターフェイスを使用します。

ボーナスとして、検証もユニットテスト可能です。

コレクションの場合、私は通常、CustomValidation属性と、有効とされているコレクションプロパティと同じViewModelの中のメソッドを使用します。

あなたは基本的な作業例が必要な場合は、このクラスを見て、インターフェイスを持っている:WPF Project using attribute validation

using System; 
using System.ComponentModel; 
using System.Linq.Expressions; 

namespace MwoCWDropDeckBuilder.Infrastructure.Interfaces 
{ 
    public interface IValidatingBaseViewModel : IDataErrorInfo 
    { 
     bool IsValid(); 
     bool IsValid<T>(Expression<Func<T>> propertyExpression); 
    } 
} 


using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.ComponentModel.DataAnnotations; 
using System.Linq; 
using System.Linq.Expressions; 
using MwoCWDropDeckBuilder.Infrastructure.Interfaces; 

namespace MwoCWDropDeckBuilder.Infrastructure 
{ 
    public class ValidatingBaseViewModel<TModelType> : ValidatingBaseViewModel, IBaseViewModel<TModelType> 
     where TModelType : class 
    { 
     public TModelType Model { get; private set; } 

     public ValidatingBaseViewModel(TModelType modelObject) 
     { 
      Model = modelObject; 
     } 
    } 


    public class ValidatingBaseViewModel : BaseViewModel, IValidatingBaseViewModel 
    { 
     private Dictionary<string, bool> _validationResults = new Dictionary<string, bool>(); 

     public string Error 
     { 
      get { return null; } 
     } 

     public string this[string propertyName] 
     { 
      get { return OnValidate(propertyName); } 
     } 

     public bool IsValid() 
     { 
      var t = GetType(); 
      var props = t.GetProperties().Where(
       prop => Attribute.IsDefined(prop, typeof(ValidationAttribute))); 
      return props.All(x => IsValid(x.Name)); 

     } 

     public bool IsValid<T>(Expression<Func<T>> propertyExpression) 
     { 
      var propertyName = GetPropertyName(propertyExpression); 
      return IsValid(propertyName); 
     } 

     private bool IsValid(string propertyName) 
     { 
      OnValidate(propertyName); 
      return _validationResults[propertyName]; 
     } 

     private string OnValidate(string propertyName) 
     { 
      if (string.IsNullOrEmpty(propertyName)) 
      { 
       throw new ArgumentException("Invalid property name", propertyName); 
      } 

      string error = string.Empty; 
      var value = GetValue(propertyName); 

      var t = GetType(); 
      var props = t.GetProperties().Where(
       prop => Attribute.IsDefined(prop, typeof(ValidationAttribute))); 
      if (props.Any(x => x.Name == propertyName)) 
      { 

       var results = new List<ValidationResult>(1); 
       var result = Validator.TryValidateProperty(
        value, 
        new ValidationContext(this, null, null) 
        { 
         MemberName = propertyName 
        }, 
        results); 

       StoreValidationResult(propertyName, result); 

       if (!result) 
       { 
        var validationResult = results.First(); 
        error = validationResult.ErrorMessage; 
       } 
      } 
      return error; 
     } 

     private void StoreValidationResult(string propertyName, bool result) 
     { 
      if (_validationResults.ContainsKey(propertyName) == false) 
       _validationResults.Add(propertyName, false); 
      _validationResults[propertyName] = result; 
     } 

     #region Privates 

     private string GetPropertyName<T>(Expression<Func<T>> propertyExpression) 
     { 
      var memberExpression = propertyExpression.Body as MemberExpression; 
      if (memberExpression == null) 
      { 
       throw new InvalidOperationException(); 
      } 

      return memberExpression.Member.Name; 
     } 

     private object GetValue(string propertyName) 
     { 
      object value; 
      var propertyDescriptor = TypeDescriptor.GetProperties(GetType()).Find(propertyName, false); 
      if (propertyDescriptor == null) 
      { 
       throw new ArgumentException("Invalid property name", propertyName); 
      } 

      value = propertyDescriptor.GetValue(this); 
      return value; 
     } 

     #endregion 

    } 
} 

フルプロジェクトがです

関連する問題