2009-03-03 15 views
1

In einer WPF-Seite, die ich für meine Kirche bin der Gestaltung, habe ich zwei ListBox Kontrollen an den Ergebnissen zweier gebunden Linq-to-Entities-Abfragen: die erste Listbox/Abfrage, um die Leute alle enthält, die noch nicht für das Jahr versprochen, enthält die zweite Listbox/Abfrage alle Leute, die zugesagt haben (und die damit verbundenen Zusagen). Im Einzelnen:Referenzierung Kontrollen in einer WPF-Datatemplate

var familiesWithNoPledges = from family in entities.Family.Include("Pledge") 
    where !family.Pledge.Where(p => p.PledgeYearID == pledgeYear).Any() 
    select family; 

var familiesWithPledges = from family in entities.Family 
    join pledge in entities.Pledge.Include("PledgeFrequency").Where(p => p.PledgeYearID == pledgeYear) on family equals pledge.Family 
    select new { family, pledge }; 

Wenn der Benutzer der Anwendung eine Familie aus der ersten List-Box wählt, dehnt ich das ListBox Element leicht die Felder für ein Pfand zu zeigen, so dass es einfach ist, die Versprechen Details zu der zweiten List-Box hinzuzufügen. Es sieht etwa so aus:

http://wouldbetheologian.com/images/PledgeManager.jpg (Offsite Image)

Die zugrunde liegende Datenbank (unter anderem) einen „Familie“ Tisch mit einer 1: Beziehung zu einer „Pledge“ Tabelle. Und wenn der Benutzer auf die Schaltfläche "Pledge hinzufügen" klickt, möchte ich die neue Pledge-Instanz erstellen, in der Datenbank speichern und dann die beiden Steuerelemente aktualisieren.

Aber ich kann nicht herausfinden, wie das geht. Wenn ich versuche, es im Code-Behind zu tun, scheint es nicht so, als ob der Event-Handler für die (n-Instanzen der) "Add Pledge" -Schaltfläche auf die betreffenden Steuerelemente verweisen könnte; Wenn ich in XAML versuche, die ListBoxItem-DataTemplate-Steuerelemente an die Felder Family.Pledge (oder Family.Pledge.FirstOrDefault()) zu binden, sind diese Felder immer noch leer, wenn ich das aktuelle Family-Objekt im Ereignishandler für Add anschaue Pledge-Taste.

Irgendwelche Gedanken, wie man das löst? Oder gibt es ein besseres UI-Modell, das ich insgesamt betrachten sollte?

Vielen Dank im Voraus.

Antwort

2

Danke, Andrew, das hat es getan. Der Schlüssel war, dass ich einen separaten DataContext für das fragliche DockPanel erstellen und dann an eine neue Instanz des Pledge-Objekts binden musste, das höher in der Vorlage erstellt wurde.

<ListBox> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <Grid> 
       <Grid.Resources> 
        <local:Pledge x:Key="pledge" /> 
       </Grid.Resources> 

       <DockPanel DataContext="{Binding Source={StaticResource pledge}}" > 
        <TextBox Name="txtAmount" Text="{Binding Path=Amount}" /> 
        <TextBox Name="txtEnvelopeID" Text="{Binding Path=EnvelopeID}" /> 
        <!-- Bind the Tag property of the Button to the DataContext of the ListBoxItem, i.e. the current Family object --> 
        <Button Tag="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext}" Name="addPledge" Click="addPledge_Click" > 
         Add Pledge --> 
        </Button> 
       </DockPanel> 
      </Grid> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

Ich brauchte noch mehr Details zu Setup entsprechend die Pledge Objekt zu wissen, aber ich war in der Lage, sie zu erhalten, indem die Schaltfläche Tag-Eigenschaft auf die Datacontext seiner Templat-Mutterbindung:

<Button 
    Tag="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext}" 
    Name="addPledge" 
    Click="addPledge_Click" 
/> 

Und von dort aus konnte ich den Rest in Code-behind zu handhaben:

private void addPledge_Click(object sender, RoutedEventArgs e) 
    { 
     try 
     { 
      // Set any additional necessary properties. 
      Button button = (Button)sender; 
      Pledge pledge = (Pledge)button.DataContext; 
      pledge.PledgeYear = (PledgeYear)cboYear.SelectedItem; 
      pledge.Family = (Family)button.Tag; 

      // Update the database and refresh the Listboxes. 
      entities.AddToPledge(pledge); 
      entities.SaveChanges(); 
      LoadUnpledgedListBox(); 
      LoadPledgedListBox(); 
     } 
     catch (System.Data.UpdateException ex) 
     { 
      MessageBox.Show("Error updating database: " + ex.Message); 
     } 
     catch (System.Exception ex) 
     { 
      Classes.Utils.HandleGenericError(ex); 
     } 
    } 

Vielen dank -, die mich in die richtige Richtung.

2

Der einfachste Weg, es zu tun ist, um die Klasse zu haben, die Itemssource-Artikel im List-Box wird stellvertretend für alle Felder, die Sie in Ihrem Datatemplate Referenzierung werden. Dann können Sie in Ihrem Button-Handler auf die neuen Pfandinformationen zugreifen, indem Sie den Datenkontext der Schaltfläche verwenden.

private void AddPledge_Click(object sender, RoutedEventArgs e) 
    { 
     Button b = sender as Button; 
     PotentialPledge p = b.DataContext as PotentialPledge; 

     //do stuff with pledge 
    } 

Es könnte eine Möglichkeit, dies ohne zu tun, die als Templat Felder Teil der Klasse sein, die die Itemssource für die List-Box macht (nur WPF selbst zu lernen), aber das funktioniert. Wenn das nicht hilft, schaue ich später zurück (zur Arbeit).

Wie auch immer, tolle Arbeit, eine App für Ihre Kirche zu machen, es sieht ziemlich gut.