Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get item from template in ItemsControl

I have an ItemsControl that is populated with an observable collection of some ViewModel classes, like so:

<ItemsControl ItemsSource="{Binding MyCollection}">
  <ItemsControl.ItemTemplate>
    <DataTemplate Type="{x:Type local:MyViewModel}">
      <Button Content="{Binding ActionName}" Click="ClickHandler"/>
    </DataTemplate>
  <ItemsControl.ItemTemplate>
</ItemsControl>

Works great, looks great, but I can't seem to figure out how to get the "ClickHandler" to be aware of the class 'MyViewModel' that is represented by the data template. Behold!

private void ClickHandler(object sender, RoutedEventArgs e)
{
  // The 'sender' is the button that raised the event.  Great!
  // Now how do I figure out the class (MyViewModel) instance that goes with this button?
}
like image 599
A.R. Avatar asked Dec 12 '22 14:12

A.R.


2 Answers

OK duh, I almost immediately realized that it is the 'DataContext' of the 'sender'. I am going to leave this up unless the community thinks that this question is just too obvious.

private void ClickHandler(object sender, RoutedEventArgs e)
{
  // This is the item that you want.  Many assumptions about the types are made, but that is OK.
  MyViewModel model = ((sender as FrameworkElement).DataContext as MyViewModel);
}
like image 157
A.R. Avatar answered Dec 25 '22 22:12

A.R.


Your own answer will do the trick in this specific case. Here's another technique which, while much more complicated, will also work on any scenario regardless of complexity:

Starting from sender (which is a Button), use VisualTreeHelper.GetParent until you find a ContentPresenter. This is the type of UIElement that the ItemTemplate you specified is hosted into for each of your items. Let's put that ContentPresenter into the variable cp. (Important: if your ItemsControl were a ListBox, then instead of ContentPresenter we 'd look for a ListBoxItem, etc).

Then, call ItemsControl.ItemContainerGenerator.ItemFromContainer(cp). To do that, you will need to have some reference to the specific ItemsControl but this shouldn't be hard -- you can, for example, give it a Name and use FrameworkElement.FindName from your View itself. The ItemFromContainer method will return your ViewModel.

All of this I learned from the stupidly useful and eye-opening posts of Dr. WPF.

like image 21
Jon Avatar answered Dec 25 '22 20:12

Jon