2016-05-12 21 views
1

私は、文字列アイテムのListBoxを使用して、文字列を追加または削除するたびにその文字列を検証したいと思っています。WPF ListBoxデータの検証

以下は私がまとめたコードですが、ObservableCollection Addressesが変更されたときにValidateAddressesが呼び出されることはありません。

無効な文字列が見つかった場合、エラーメッセージを表示するツールチップを使用して、リストボックスの周囲に赤い枠線が表示されます。

このINotifyDataErrorInfoの設定は、テキストボックスでうまくいきます。そのため、ここで間違っていることはわかりません。

のViewModel

[CustomValidation(typeof(ItemViewModel), "ValidateAddresses")] 
public ObservableCollection<string> Addresses 
{ 
    get 
    { 
     return item.Addresses; 
    } 

    set 
    { 
     item.Addresses = value; 
     NotifyPropertyChanged(nameof(Addresses)); 
    } 
} 

XAML

<Grid> 
    <Grid.Resources> 
     <Style TargetType="ListBox"> 
      <Setter Property="Margin" Value="5"/> 
      <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/> 
      <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/> 

      <Setter Property="Validation.ErrorTemplate"> 
       <Setter.Value> 
        <ControlTemplate x:Name="TextErrorTemplate"> 
         <DockPanel LastChildFill="True"> 
          <AdornedElementPlaceholder> 
           <Border BorderBrush="Red" BorderThickness="2"/> 
          </AdornedElementPlaceholder> 
          <TextBlock Foreground="Red"/> 
         </DockPanel> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 

      <Style.Triggers> 
       <Trigger Property="Validation.HasError" Value="True"> 
        <Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors).CurrentItem.ErrorContent}"/> 
       </Trigger> 
      </Style.Triggers> 
     </Style> 
    </Grid.Resources> 

    <ListBox ItemsSource="{Binding Path=Item.Addresses, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnNotifyDataErrors=True}" SelectedIndex="{Binding Path=SelectedAddress, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> 
</Grid> 

検証方法(と呼ばれることはありません)

public static ValidationResult ValidateAddresses(object obj, ValidationContext context) 
{ 
    ItemViewModel item = (ItemViewModel)context.ObjectInstance; 

    if (item.Addresses.Count > 0) 
    { 
     foreach (string address in item.Addresses) 
     { 
      if (Regex.IsMatch(address, @"[^\w]")) 
       return new ValidationResult($"{address} is not a valid address.", new List<string> { "Addresses" }); 
     } 
    } 

    return ValidationResult.Success; 
} 
+0

なぜ 'Addresses'のゲッターとセッターが' item'を参照していますか? – niksofteng

+0

'item'はINotifyPropertyChangedとINotifyDataErrorInfoから継承したクラスで、ObservableCollection Addressesはどこのクラスです。 XAMLとValidateAddressesは 'item'も参照します。 – KeeperB5

+0

これはおそらくポイントです。あなたは 'Itemress'ではなく' Adresses'にバインドする必要があります。 – Sinatr

答えて

0

私は私が持っていた各のObservableCollectionのクラスのコンストラクタに、以下を追加してしまいました。

Addresses.CollectionChanged += (sender, eventArgs) => { NotifyPropertyChanged(nameof(Addresses)); }; 

私はイベントから退会がメモリリークを防ぐために必要とされる時に状況を検討しようとしたが、これはこれらのケースの一つであるようにクリーンアップが要求されるべきではないので、それはいないようです。

ObservableCollectionsがすべてModelクラスコンストラクタで初期化されるため、NULLチェックは不要です。

あなたの返信ありがとうございます。

これはNotifyPropertyChangedのコードです。

public class ObservableObject : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    protected void NotifyPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 
}