2

在我为我的教堂设计的 WPF 页面中,我有两个 ListBox 控件绑定到两个 Linq-to-Entities 查询的结果:第一个列表框/查询包含所有今年尚未承诺的人,第二个列表框/查询包含所有已承诺的人(及其相关的承诺)。具体来说:

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

当应用程序的用户从第一个 ListBox 中选择一个家庭时,ListBox 项会略微扩展以显示承诺的字段,以便将承诺详细信息添加到第二个 ListBox。它看起来像这样:

http://wouldbetheologian.com/images/PledgeManager.jpg (非现场图片)

底层数据库(除其他外)有一个“家庭”表,与“承诺”表具有 1:many 关系。而当用户点击“Add Pledge”按钮时,我想创建新的Pledge实例,保存到数据库中,然后刷新两个控件。

但我不知道该怎么做。如果我尝试在代码隐藏中执行此操作,则“添加承诺”按钮的(n 个实例)的事件处理程序似乎无法引用相关控件;在 XAML 中,如果我尝试将 ListBoxItem DataTemplate 控件绑定到 Family.Pledge(或 Family.Pledge.FirstOrDefault())字段,当我查看 Add 事件处理程序中的当前 Family 对象时,这些字段仍然为空承诺按钮。

关于如何解决这个问题的任何想法?或者有没有更好的 UI 模型我应该完全看一下?

提前致谢。

4

2 回答 2

2

最简单的方法是让表示 ListBox ItemsSource 中的项目的类具有您在 DataTemplate 中引用的所有字段。然后在您的按钮处理程序中,您可以使用按钮的数据上下文访问新的承诺信息。

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

        //do stuff with pledge
    }

可能有一种方法可以做到这一点,而无需模板化字段成为构成 ListBox 的 ItemsSource 的类的一部分(我自己只是学习 WPF),但这有效。如果这没有帮助,我稍后再回头(现在开始工作)。

无论如何,为你的教会制作一个应用程序真是太棒了,它看起来很不错。

于 2009-03-03T07:05:15.123 回答
2

谢谢,安德鲁,做到了。关键是我必须为有问题的 DockPanel 创建一个单独的 DataContext,然后将它绑定到在模板中创建的 Pledge 对象的新实例。

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

我仍然需要了解更多详细信息才能正确设置 Pledge 对象,但我能够通过将 Button 的 Tag 属性绑定到其模板化父对象的 DataContext 来获取它们:

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

从那里,我能够在代码隐藏中处理其余部分:

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

非常感谢——这为我指明了正确的方向。

于 2009-03-03T09:48:42.267 回答