Вопрос

На странице 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 };

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

http://wouldbetheologian.com/images/PledgeManager.jpg (Удаленное изображение)

Базовая база данных (среди прочего) имеет таблицу "Family" с отношением 1: many к таблице "Pledge".И когда пользователь нажимает кнопку "Добавить залог", я бы хотел создать новый экземпляр залога, сохранить его в базе данных, а затем обновить два элемента управления.

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

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

Заранее благодарю.

Это было полезно?

Решение 2

Спасибо, Эндрю, у тебя получилось.Ключевым моментом было то, что мне пришлось создать отдельный 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>

Мне все еще нужно было знать больше деталей, чтобы соответствующим образом настроить объект залога, но я смог получить их, привязав свойство тега Button к DataContext его шаблонного родительского элемента:

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

И с этого момента я смог справиться с остальным в 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);
        }
    }

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

Другие советы

Самый простой способ сделать это - сделать так, чтобы класс, представляющий элементы в вашем 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 сам), но это работает.Если это не поможет, я загляну к вам позже (а сейчас отправляюсь на работу).

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top