Reputation: 1029
I am binding my ListBox to an items collection, which contains instances of my Item's class.
This part works as expected. The problem i'm having is accessing the clicked ListBox items item
instance. I have included the full example and the relevant XAML.
I have also included an example of how I would like to access the Item
instance inside the listBoxItems_PreviewMouseDown
event handler.
I assume i'm missing something obvious, but the code crashes when I click an item. Am I missing another binding to glue all of this together?
Thank you
Code behind:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Threading;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
// Item class
internal class Item : INotifyPropertyChanged
{
public Item(string name = null)
{
this.Name = name;
}
public string Name { get; set; }
public string ImagePath { get; set; }
public string SomeString { get; set; }
public int SomeInt { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
// Item collection
ObservableCollection<Item> ItemsCollection;
public MainWindow()
{
InitializeComponent();
// Initialize the items collection
this.ItemsCollection = new ObservableCollection<Item>();
for (int i = 0; i < 5; i ++)
{
Dispatcher.Invoke(new Action(() =>
{
Item newItem = new Item
{
Name = "test " + i,
ImagePath = @"Images\" + i + ".jpg",
SomeString = "example" + i,
SomeInt = i,
};
// Add the new item to the collection
this.ItemsCollection.Add(newItem);
}), DispatcherPriority.Background);
}
// Set the items source
this.listBoxItems.ItemsSource = this.ItemsCollection;
}
// Handle mouse down events on listbox items
private void listBoxItems_PreviewMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
// Ideally, i'd like to do something like this
Item item = sender as Item;
// So then I could do for example
Console.WriteLine(@"Clicked item SomeString: {0}, SomeInt {1}", item.SomeString, item.SomeInt);
}
}
}
XAML:
<userControls:MyListBox x:Name="ItemsListBox" ItemsSource="{Binding ItemsCollection}" PreviewMouseDown="listBoxItems_PreviewMouseDown">
<ListBox.ItemTemplate>
<DataTemplate>
<VirtualizingStackPanel>
<Image Source="{Binding ImagePath}" Width="200" Height="100"/>
<TextBlock Text="{Binding Name}" />
</VirtualizingStackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</userControls:MyListBox>
Upvotes: 1
Views: 414
Reputation: 3646
Besides the accepted answer, alternatively you can bind the PreviewMouseDown
event directly to the ListBoxItem
.
In that case the XAML can be (emphasis on the added <ListBox.ItemContainerStyle>
node):
<userControls:MyListBox x:Name="ItemsListBox" ItemsSource="{Binding ItemsCollection}" PreviewMouseDown="listBoxItems_PreviewMouseDown">
<ListBox.ItemTemplate>
<DataTemplate>
<VirtualizingStackPanel>
<Image Source="{Binding ImagePath}" Width="200" Height="100"/>
<TextBlock Text="{Binding Name}" />
</VirtualizingStackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<EventSetter Event="PreviewMouseDown" Handler="listBoxItems_PreviewMouseDown" />
</Style>
</ListBox.ItemContainerStyle>
</userControls:MyListBox>
And the handler:
// Handle mouse down events on listbox items
private void listBoxItems_PreviewMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
// Ideally, i'd like to do something like this
Item item = (sender as ListBoxItem).DataContext as Item;
// So then I could do for example
Console.WriteLine(@"Clicked item SomeString: {0}, SomeInt {1}", item.SomeString, item.SomeInt);
}
Upvotes: 2
Reputation: 1578
You can get the OriginalSource
of the event and examine its DataContext
:
var item = (e.OriginalSource as FrameworkElement)?.DataContext as Item;
if (item != null) { /* Do something with item... */ }
Upvotes: 1