+2  A: 

The easiest way to do it is to have the class that is representing items in your ListBox ItemsSource to have all the fields that you are referencing in your DataTemplate. Then in your button handler you can access the new pledge info by using the data context of the button.

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

        //do stuff with pledge
    }

There might be a way to do this without having the templated fields be part of the class that makes up the ItemsSource for the ListBox (just learning WPF myself), but this works. If that doesn't help, I'll look back later (off to work now).

Anyway, awesome job making an app for your church, it's looking pretty good.

Andrew Barrett
+2  A: 

Thanks, Andrew, that did it. The key was that I had to create a separate DataContext for the DockPanel in question, and then bound it to a new instance of the Pledge object created higher up in the template.

<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>

I still needed to know more details to setup the Pledge object appropriately, but I was able to get them by binding the Button's Tag property to the DataContext of its templated parent:

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

And from there, I was able to handle the rest in code-behind:

 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);
  }
 }

Many thanks -- that pointed me in the right direction.

Ken Smith