WPF ListBoxItems with DataTemplates - How do I reference the CLR Object bound to ListBoxItem from within the DataTemplate?

£可爱£侵袭症+ 提交于 2019-11-29 18:48:54

问题


I have a ListBox, that's bound to an ObservableCollection.

Each ListBoxItem is displayed with a DataTemplate. I have a button in my DataTemplate, that when clicked, needs a reference to the member of the ObservableCollection it's part of the DataTemplate for. I can't use the ListBox.SelectedItem property because the item does not become selected when clicking the button.

So either: I need to figure out how to properly set ListBox.SelectedItem when the mouse hovers, or when the button is clicked. Or I need to figure out another way to get a reference to the CLR Object bound to the ListBoxItem that the button belongs to. The second option seems cleaner, but either way is probably OK.

Simplified code segment below:

XAML:

<DataTemplate x:Key="postBody">
    <Grid>
        <TextBlock Text="{Binding Path=author}"/>
        <Button Click="DeleteButton_Click">Delete</Button>
    </Grid>
</DataTemplate>

<ListBox ItemTemplate="{StaticResource postBody}"/>

C#:

private void DeleteButton_Click(object sender, RoutedEventArgs e)
{
    Console.WriteLine("Where mah ListBoxItem?");
}

回答1:


Generally speaking people will be interested in a CLR object directly bound to the ListBoxItem, not the actual ListBoxItem. If you had a list of posts for example you could use your existing template of:

<DataTemplate x:Key="postBody" TargetType="{x:Type Post}">
  <Grid>
    <TextBlock Text="{Binding Path=author}"/>
    <Button Click="DeleteButton_Click">Delete</Button>
  </Grid>
</DataTemplate>
<ListBox ItemTemplate="{StaticResource postBody}" 
  ItemSource="{Binding Posts}"/>

and in your code-behind, your Button's DataContext is equal to your DataTemplate's DataContext. In this case a Post.

private void DeleteButton_Click(object sender, RoutedEventArgs e){
  var post = ((Button)sender).DataContext as Post;
  if (post == null)
    throw new InvalidOperationException("Invalid DataContext");

  Console.WriteLine(post.author);
}



回答2:


You have several possibilities, depending on what you need to do.

First, the main question is: "why do you need this"? Most of the time, there is no real use for a reference to the container item (not saying this is your case, but you should elaborate). If you are databinding your listbox, there is rarely a case for that.

Second, you can get the item from the Listbox, using myListBox.ItemContainerGenerator.ContainerFromItem(), provided your listbox is named MyListBox. From the sender parameter, you can get back the actual item that was templated through, for example (where XXX is the type of you databound data):

Container = sender as FrameworkElement;
if(sender != null)
{
    MyItem = Container.DataContext as XXX;
    MyElement = MyListBox.ItemContainerGenerator.ContainerFromItem(MyItem); // <-- this is your ListboxItem.
}

You can find an example an this blog. She uses the index method, but the Item method is similar.



来源:https://stackoverflow.com/questions/765984/wpf-listboxitems-with-datatemplates-how-do-i-reference-the-clr-object-bound-to

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!