Problem with traversing WPF element tree
-
29-09-2019 - |
Question
I have a ListBox
data bound to the collection of my PersonCollection
class. Next, I have defined a data template for objects of type Person
, consisted of a DockPanel
which contains a TextBlock
for a person's name and a Button
to remove the person from the list. It looks very nice all together.
The problem I am facing is that I am unable to reach the selected item (and delete it) in the list box when I click the button defined in the data template. Here's the handler of the button:
private void RemovePersonButton_Click(object sender, RoutedEventArgs e)
{
Button clickedButton = (Button)e.Source;
DockPanel buttonPanel = (DockPanel)clickedButton.Parent;
Control control = (Control)button.Parent;
}
The last created object control
is null
, i.e. I cannot progress further up the element tree, so I cannot reach the list and its SelectedItem
. Important thing to note here is that cannot simply go with getting the selected item from the list by calling it, because I have more than one list in the window and all those lists implement the same data template, i.e. share the same event handler for the delete button.
I would appreciate all the help I could get. Thanks.
Solution
If I understand the question correctly I think you'll be able to get the Person from the Button's DataContext
private void RemovePersonButton_Click(object sender, RoutedEventArgs e)
{
Button clickedButton = (Button)e.Source;
Person selectedItem = clickedButton.DataContext as Person;
if (selectedItem != null)
{
PersonCollection.Remove(selectedItem);
}
}
Another way is to find the ListBox in the VisualTree
private void RemovePersonButton_Click(object sender, RoutedEventArgs e)
{
Button clickedButton = (Button)e.Source;
ListBox listBoxParent = GetVisualParent<ListBox>(clickedButton );
Person selectedItem = listBoxParent.SelectedItem as Person;
//...
}
public T GetVisualParent<T>(object childObject) where T : Visual
{
DependencyObject child = childObject as DependencyObject;
while ((child != null) && !(child is T))
{
child = VisualTreeHelper.GetParent(child);
}
return child as T;
}
OTHER TIPS
You might try using VisualTreeHelper.GetParent to walk the visual tree, rather than relying on the Logical Parent.
That said, you might consider whether you can wrap your Person in a PersonItem class, with additional context information so that the PersonItem knows how to remove the Person from the list. I'll sometimes use this pattern and I wrote an EncapsulatingCollection class that automatically instantiates wrapper objects based on the changes in a monitored ObservableCollection.