Ссылки на элементы управления в шаблоне данных WPF - PullRequest
1 голос
/ 03 марта 2009

На странице 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: много к таблице «Залог». И когда пользователь нажимает кнопку «Добавить залог», я хотел бы создать новый экземпляр залога, сохранить его в базе данных и затем обновить два элемента управления.

Но я не могу понять, как это сделать. Если я попытаюсь сделать это в коде, это не похоже на то, что обработчик события для (n-экземпляров) кнопки «Добавить залог» может ссылаться на рассматриваемые элементы управления; и в XAML, если я пытаюсь привязать элементы управления ListBoxItem DataTemplate к полям Family.Pledge (или Family.Pledge.FirstOrDefault ()), эти поля все еще остаются пустыми, когда я смотрю на текущий объект Family в обработчике события для Add Кнопка залога.

Есть мысли, как это решить? Или есть лучшая модель пользовательского интерфейса, на которую я должен смотреть в целом?

Заранее спасибо.

Ответы [ 2 ]

2 голосов
/ 03 марта 2009

Спасибо, Андрей, это сделал. Ключевым моментом было то, что мне пришлось создать отдельный DataContext для рассматриваемой DockPanel, а затем связать его с новым экземпляром объекта 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, но я смог получить их, связав свойство Tag Button с 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);
        }
    }

Большое спасибо - это указало мне правильное направление.

2 голосов
/ 03 марта 2009

Самый простой способ сделать это - иметь класс, представляющий элементы в вашем 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
    }

Возможно, есть способ сделать это, не добавляя шаблонные поля в класс, который составляет ItemsSource для ListBox (я просто изучаю WPF), но это работает. Если это не поможет, я посмотрю позже (сейчас на работу).

В любом случае, отличная работа по созданию приложения для вашей церкви, это выглядит довольно хорошо.

...