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