2017-08-07 8 views
0

マスターディテールビューのプロジェクトがあります。マスターディテールにはオブジェクトを選択するリストがあり、ディテールパートにはそのオブジェクトの詳細が表示され、編集が可能です。マスターディテール検証WPF

私の問題は、2つのオブジェクトに同じ名前を付けることができないということです。このサウンドは簡単な作業のようですが、私が知っている検証プロセスがうまく機能しないことがわかります。

ここでは簡単な例を示します。

XAML

<Window x:Class="WpfApplication1.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:WpfApplication1="clr-namespace:WpfApplication1" 
     mc:Ignorable="d" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="*"/> 
      <ColumnDefinition Width="2*"/> 
     </Grid.ColumnDefinitions> 
     <ListView Grid.Column="0" ItemsSource="{Binding Path=People, ValidatesOnDataErrors=True, NotifyOnValidationError=True}" Name="masterList" 
       DisplayMemberPath="Name" SelectedItem="{Binding Path=SelectedPerson}" /> 

     <StackPanel Grid.Column="1" Margin="5" DataContext="{Binding Path=SelectedPerson}"> 
      <TextBlock>Name</TextBlock> 
      <TextBox> 
       <TextBox.Text> 
        <Binding Path="Name" Mode="TwoWay" ValidatesOnDataErrors="True" NotifyOnValidationError="True"> 
        </Binding> 
       </TextBox.Text> 
      </TextBox> 
      <TextBlock>Address</TextBlock> 
      <TextBox Text="{Binding Path=Address}" /> 
      <TextBlock>Phone</TextBlock> 
      <TextBox Text="{Binding Path=Phone}" /> 
     </StackPanel> 
    </Grid> 
</Window> 

Personクラス

using System; 
using System.ComponentModel; 
using System.Runtime.CompilerServices; 

public class Person { 
    public string Name { get; set; } 
    public string Address { get; set; } 
    public string Phone { get; set; } 
} 

RegisteredPeopleクラス

public class RegisteredPeople { 
    public ObservableCollection<Person> People { get; set; } 
    public Person SelectedPerson { get; set; } 
    public RegisteredPeople() { 
     People = new ObservableCollection<Person>() { 
      new Person() {Name = "Ramzi", Address = "A1", Phone = "1"}, 
      new Person() {Name = "Frank", Address = "A2", Phone = "12"}, 
      new Person() {Name = "Ihab", Address = "A3", Phone = "123"} 
     }; 
    } 
} 

これはありません検証はありませんが、私が望む基本的な仕組みを示しています。

Personクラスの他の実施

using System; 
using System.ComponentModel; 
using System.Runtime.CompilerServices; 

public class Person : System.ComponentModel.IDataErrorInfo, INotifyPropertyChanged { 
    private string m_name; 

    public string Name { 
     get { return m_name; } 
     set { 
      m_name = value; 
      OnPropertyChanged(); 
      OnPropertyChanged("People"); //Name of the list that the master list is bound to. 
     } 
    } 

    public string Address { get; set; } 
    public string Phone { get; set; } 

    public string this[string columnName] { 
     get { 
      switch (columnName) { 
       case "Name": 
        if (string.IsNullOrEmpty(Name)) { 
      /** This one works, but from here I cannot compare with names of other Person objects. **/ 
         return "The name cannot be empty."; 
        } 
        break; 
       default: 
        return string.Empty; 
      } 
      return String.Empty; 
     } 
    } 

    public string Error { get; } 
    public event PropertyChangedEventHandler PropertyChanged; 

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

RegisteredPeopleクラスの他の実施


は、私がどんな成功せず、両方のクラスにIDataErrorInfoを実装しようとしています

public class RegisteredPeople : System.ComponentModel.IDataErrorInfo { 
    public ObservableCollection<Person> People { get; set; } 
    public Person SelectedPerson { get; set; } 
    public RegisteredPeople() { 
     People = new ObservableCollection<Person>() { 
      new Person() {Name = "Ramzi", Address = "A1", Phone = "1"}, 
      new Person() {Name = "Frank", Address = "A2", Phone = "12"}, 
      new Person() {Name = "Ihab", Address = "A3", Phone = "123"} 
     }; 
    } 

    public string this[string columnName] { 
     get { 
      switch (columnName) { 
       case "People": 
        foreach (Person person1 in People) { 
         foreach (Person person2 in People) { 
          if (person1 == person2) { 
           continue; 
          } 
          if (person1.Name == person2.Name) { 
           return "Error, 2 people cannot have the same name."; 
          } 
         } 
        } 
        break; 
       default: 
        return string.Empty; 
      } 
      return string.Empty; 
     } 
    } 

    public string Error { get; } 
} 

また、私はValidationRuleインターフェイスでうまくいくことなく試してみました。ここで

は、私が試したものです:

XAML

私は名のテキストボックスを置き換える:

 <TextBox> 
      <TextBox.Text> 
       <Binding Path="Name" Mode="TwoWay" ValidatesOnDataErrors="True" NotifyOnValidationError="True"> 
        <Binding.ValidationRules> 
         <WpfApplication1:EventNameValidationRule EventList="{Binding ElementName=masterList, Path=ItemsSource}" /> 
        </Binding.ValidationRules> 
       </Binding> 
      </TextBox.Text> 
     </TextBox> 

EventNameValidationRule

using System.Collections.ObjectModel; 
using System.Globalization; 
using System.Windows.Controls; 

class EventNameValidationRule : ValidationRule { 
    public ObservableCollection<Person> EventList { get; set; } 
    public override ValidationResult Validate(object value, CultureInfo cultureInfo) { 
     return new ValidationResult(false, "Duplicate names are not allowd."); 
    } 
} 

事は、EventListへのバインディングが良くないと言うこのような例外がスローされます。 (このリストがなければ、私は明らかに比較する内容のない出発点を持っていません。)


私の質問:にはどうすれば有効ではないとして名をマークすることができ、2 peoleは、同じ名前が呼ばれたときに?

+0

はたぶん、あなたは、あなたがのValidationRuleと試みた何を教えなければならない方法を作成することができます。 ValidationRuleを使用すると、私のために行く方法のようです。 ValidationRuleにリストをバインドしようとすると(その方法:http://dedjo.blogspot.de/2007/05/fully-binded-validation-by-using.html)、Validateメソッドが呼び出されると、指定された名前を持つ複数の項目が含まれている場合、ValidationRuleにバインドしたリストをチェックします。 –

+0

ありがとう@ Dr.Coconut私の編集を参照してください。 –

答えて

3

IDataErrorInfoインターフェイスを実装する実際のDataContextPersonクラスに検証ロジックを実装する必要があります。

あなたは、たとえば、あなたがPersonクラスのインデクサから呼び出すあなたのRegisteredPeopleクラス、.e.g:

public class Person : IDataErrorInfo, INotifyPropertyChanged 
{ 
    private readonly IValidator _validator; 
    public Person(IValidator validator) 
    { 
     _validator = validator; 
    } 

    private string m_name; 
    public string Name 
    { 
     get { return m_name; } 
     set 
     { 
      m_name = value; 
      OnPropertyChanged(); 
     } 
    } 

    public string Address { get; set; } 
    public string Phone { get; set; } 

    public string this[string columnName] 
    { 
     get 
     { 
      switch (columnName) 
      { 
       case "Name": 
        if (string.IsNullOrEmpty(Name)) 
        { 
         /** This one works, but from here I cannot compare with names of other Person objects. **/ 
         return "The name cannot be empty."; 
        } 
        else 
        { 
         return _validator.Validate(this); 
        } 
       default: 
        return string.Empty; 
      } 
     } 
    } 

    public string Error { get; } 
    public event PropertyChangedEventHandler PropertyChanged; 

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

public interface IValidator 
{ 
    string Validate(Person person); 
} 

public class RegisteredPeople : IValidator 
{ 
    public ObservableCollection<Person> People { get; set; } 
    public Person SelectedPerson { get; set; } 

    public string Validate(Person person) 
    { 
     if (person != null && People.Any(x => x != person && x.Name == person.Name)) 
      return "Same name!"; 

     return null; 
    } 

    public RegisteredPeople() 
    { 
     People = new ObservableCollection<Person>() { 
     new Person(this) {Name = "Ramzi", Address = "A1", Phone = "1"}, 
     new Person(this) {Name = "Frank", Address = "A2", Phone = "12"}, 
     new Person(this) {Name = "Ihab", Address = "A3", Phone = "123"} 
    }; 
    } 
} 
関連する問題