问题
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