2009-07-31 2 views
3

Ich habe seit ein paar Tagen nach einer Antwort auf meine Frage gesucht, bin aber nicht in der Lage, eine Lösung zu finden.WPF Master-Details Ansicht mit Listbox und Combobox mit Binding

Das Problem besteht darin, dass die Combobox das Testobjekt in der Benutzerklasse mit den zuvor ausgewählten Benutzern aktualisiert.

d. H., Sie wählen user2 und user2 hat test2, dann wählen Sie user5 mit test5 aus. Wenn Sie nun erneut user2 auswählen, wird angezeigt, dass test5 vorhanden ist.

Hier ist ein Code. Ich habe zwei Klassen Benutzer und Tests. Und zwei ObservableCollections für jeden von denen. Dies ist, wie ich habe sie Setup bekam:

public class User 
{ 
    public string Name { get; set; } 
    public int test { get; set; } 
    public test userTest { get; set; } 
} 

public class test 
{ 
    public int ID { get; set; } 
    public String Name { get; set; } 
} 

public class ListOfTests:ObservableCollection<test> 
{ 
    public ListOfTests() 
    { 
     for (int i = 0; i < 4; i++) 
     { 
      test newTest = new test(); 
      newTest.ID = i; 
      newTest.Name = "Test " + i; 
      Add(newTest); 
     } 
    } 
} 

public class ListOfUsers: ObservableCollection<User> 
{ 
    public ListOfUsers() 
    { 
     ListOfTests testlist = new ListOfTests(); 
     for (int i = 0; i < 10; i++) 
     { 
      User newUser = new User(); 
      newUser.Name = "User " + i; 
      newUser.ID = i; 
      newUser.userTest = testlist[i]; 
      Add(newUser); 
     } 
    } 
} 

Und die XAML ist:

<Window x:Class="ComboboxTest.Window1" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:local="clr-namespace:ComboboxTest" 
Title="Window1" Height="300" Width="300"> 
<StackPanel x:Name="SP1"> 
    <StackPanel.Resources> 
     <local:ListOfTests x:Key="ListOfTests" /> 
    </StackPanel.Resources> 
    <ListBox ItemsSource="{Binding}" DisplayMemberPath="Name" IsSynchronizedWithCurrentItem="True"/> 
    <TextBox Text="{Binding Path=Name}" Foreground="Black" /> 
    <TextBox Text="{Binding Path=userTest}" /> 
    <ComboBox SelectedItem="{Binding Path=userTest}" 
       SelectedValue="{Binding Path=userTest.ID}" 
       ItemsSource="{Binding Source={StaticResource ListOfTests}}" 
       DisplayMemberPath="Name" 
       SelectedValuePath="ID" 

       Foreground="Black" /> 
</StackPanel> 

Nun, wenn ich die Bindung an die SelectedItem „{Binding Path = Usertest ändern, Modus = OneWay} "dann funktioniert es, aber ich kann es nicht manuell ändern.

Hier ist ein Kicker gedacht ... Wenn ich .Net 4.0 (VS2010) Ziel dann funktioniert es gut ...

Kann jemand mir bitte helfen, eine Lösung für dieses Problem zu finden?

Antwort

5

Wenn ich Ihre Frage verstehe, klingt es so, dass WPF nicht benachrichtigt wird, wenn sich der Wert einer Eigenschaft ändert. Sie können dies umgehen, indem Sie die INotifyPropertyChanged Schnittstelle implementieren. so etwas wie dies zum Beispiel würde die User Klasse aussehen:

public class User : INotifyPropertyChanged 
{ 
    private string name = string.Empty; 
    public string Name 
    { 
     get { return this.name; } 
     set 
     { 
      this.name = value; 
      this.OnPropertyChanged("Name"); 
     } 
    } 

    private int test = 0; 
    public int Test 
    { 
     get { return this.test; } 
     set 
     { 
      this.test = value; 
      this.OnPropertyChanged("Test"); 
     } 
    } 

    private test userTest = null; 
    public test UserTest 
    { 
     get { return this.userTest; } 
     set 
     { 
      this.userTest = value; 
      this.OnPropertyChanged("UserTest"); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    private void OnPropertyChanged(string propName) 
    { 
     PropertyChangedEventHandler eh = this.PropertyChangd; 
     if(null != eh) 
     { 
      eh(this, new PropertyChangedEventArgs(propName)); 
     } 
    } 
} 

Sie sollten wahrscheinlich für Ihre test Klasse das gleiche tun, wie gut.

WPF überwacht, wann das Ereignis PropertyChanged ausgelöst wird, und aktualisiert alle betroffenen Bindungen nach Bedarf. Dies sollte dazu führen, dass das ausgewählte Element in ComboBox zurück zum Test für Benutzer2 wechselt.

Update: OK, ich denke, ich habe das funktioniert. Ich denke, dass Sie einen Teil des Codes fehlt in dem, was Sie auf dem Laufenden (wie das, was die DataContext für die Window ist), aber hier ist, was ich habe Arbeit:

Ich habe eine Klasse ViewModel genannt, die dem DataContext gesetzt der Haupt Window. Hier ist der Code:

class ViewModel : INotifyPropertyChanged 
{ 
    public ViewModel() 
    { 
     for(int i = 0; i < 4; i++) 
     { 
      this.tests.Add(new Test() 
      { 
       ID = i, 
       Name = "Test " + i.ToString(), 
      }); 
     } 

     for(int i = 0; i < 4; i++) 
     { 
      this.users.Add(new User() 
      { 
       Name = "User " + i.ToString(), 
       ID = i, 
       UserTest = this.tests[i], 
      }); 
     } 
    } 

    private ObservableCollection<User> users = new ObservableCollection<User>(); 
    public IEnumerable<User> Users 
    { 
     get { return this.users; } 
    } 

    private ObservableCollection<Test> tests = new ObservableCollection<Test>(); 
    public IEnumerable<Test> Tests 
    { 
     get { return this.tests; } 
    } 

    private User currentUser = null; 
    public User CurrentUser 
    { 
     get { return this.currentUser; } 
     set 
     { 
      this.currentUser = value; 
      this.OnPropertyChanged("CurrentUser"); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    private void OnPropertyChanged(string propName) 
    { 
     var eh = this.PropertyChanged; 
     if(null != eh) 
     { 
      eh(this, new PropertyChangedEventArgs(propName)); 
     } 
    } 
} 

Ich habe die Erstellung der beiden Listen zu Code verschoben. Eine Sache, die ich in Ihrer Probe bemerkte, ist, dass eine Instanz von ListOfTests als von ComboBox verwendet wurde, während eine andere Instanz verwendet wurde, um ListOfUsers aufzubauen. Ich bin mir nicht sicher, ob das ein Teil des Problems war oder nicht, aber es ist besser, nur eine Liste von Tests zu haben.

Die XAML für das Haupt Window ist folgende:

<Window x:Class="WpfApplication1.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:WpfApplication1" 
    Title="Window1" Height="300" Width="300"> 
    <StackPanel> 
     <ListBox ItemsSource="{Binding Path=Users}" 
       SelectedItem="{Binding Path=CurrentUser}" 
       DisplayMemberPath="Name" 
       IsSynchronizedWithCurrentItem="True"> 
     </ListBox> 
     <TextBox Text="{Binding Path=CurrentUser.Name}" /> 
     <TextBox Text="{Binding Path=CurrentUser.UserTest.Name}" /> 
     <ComboBox ItemsSource="{Binding Path=Tests}" 
        SelectedItem="{Binding Path=CurrentUser.UserTest}" 
        DisplayMemberPath="Name" /> 
    </StackPanel> 
</Window> 

Der Schlüssel, um die Dinge arbeiten die CurrentUser Eigenschaft ist.Es ist an ListBox.SelectedItem gebunden und ComboBox.SelectedItem ist an CurrentUser.UserTest gebunden. Dadurch wird die Auswahl in ComboBox geändert, um den Test des Benutzers darzustellen, der in ListBox ausgewählt wurde.

Ich habe das alles funktioniert mit Visual Studio 2008 SP1, so hoffentlich wird es auch für Sie arbeiten. Wenn Sie Probleme haben, das funktioniert zu bekommen, lassen Sie es mich wissen und ich werde sehen, was ich tun kann.

+0

Hallo Andy, Ich habe implementiert INotifyPropertyChanged, wie Sie vorgeschlagen, aber leider bin ich immer noch das gleiche Problem bekommen. Ich habe eine Lösungsdatei auf http://cid-eddcda42d46afe81.skydrive.live.com/self.aspx/Public%20Dev/ComboboxTest.zip geschrieben Beachten Sie die Benutzernummer und die Tests Nummer sollte gleich sein. Klicken Sie nach dem Zufallsprinzip auf ein paar Benutzer und überprüfen Sie dann diejenigen, auf die Sie geklickt haben, wenn der Benutzer und der Test noch nicht ausgerichtet sind. –

+0

Ich konnte Ihre ZIP-Datei nicht öffnen. Ich habe eine Fehlermeldung erhalten, dass sie ungültig ist. Wie auch immer, macht das Objekt, das dein DataContext ist und die Eigenschaft userTest hat, auch INotifyPropertyChanged? – Andy

+0

Hallo Andy, Ja, es funktioniert ... Ich habe es als: public class User: INotifyPropertyChanged { private string name; öffentliche Zeichenkette Name ... ... privater Test userTest; öffentlicher Test UserTest { erhalten { zurück BenutzerTest; } setzen { userTest = Wert; OnPropertyChanged ("Benutzertest"); } } –

0

Andy,

Hier ist ein lesbarer Auszug aus dem Code, den ich jetzt habe.

public class User : INotifyPropertyChanged 
{ 
    private string name; 
    public string Name 
    { 
     get 
     { 
      return name; 
     } 
     set 
     { 
      name = value; 
      OnPropertyChanged("Name"); 
     } 
    } 

    private int iD; 
    public int ID 
    { 
     get 
     { 
      return iD; 
     } 
     set 
     { 
      iD = value; 
      OnPropertyChanged("ID"); 
     } 
    } 

    private test userTest; 
    public test UserTest 
    { 
     get 
     { 
      return userTest; 
     } 
     set 
     { 
      userTest = value; 
      OnPropertyChanged("UserTest"); 
     } 
    } 


    public event PropertyChangedEventHandler PropertyChanged; 
    private void OnPropertyChanged(string propName) 
    { 
     PropertyChangedEventHandler eh = this.PropertyChanged; 
     if (null != eh) 
     { 
      eh(this, new PropertyChangedEventArgs(propName)); 
     } 
    } 
} 

Sieht besser aus als in den Kommentaren.

Grüße Corne