WPF: TreeView inside a ComboBox - wpf

I'm trying to put a TreeView inside a ComboBox in WPF so that when the combo box is dropped, instead of a flat list the user gets a hierarchical list and whatever node they select becomes the selected value of the ComboBox.
I've searched quite a bit for how to accomplish this but the best I could find was only peices of potential soltuions that, because I'm ridiculously new to WPF, I couldn't make work.
I have enough knowledge of WPF and databinding that I can get my data into the treeview and I can even get the treeview inside of the combo box, however what I've been able to accomplish doesn't behave properly at all. I've attached a screenshot to show what I mean. In the screenshot the combo box is "open", so the treeview on the bottom is where I can select a node and the treeview "on top" is being drawn on top of the combobox where I want the text/value of the selected node in the tree to be displayed.
Basically what I don't know how to do is how do I get the treeview's currrently selected node to return its value back up to the combobox which then uses it as its selected value?
Here is the xaml code I'm currently using:
<ComboBox Grid.Row="0" Grid.Column="1" VerticalAlignment="Top">
<ComboBoxItem>
<TreeView ItemsSource="{Binding Children}" x:Name="TheTree">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type Core:LookupGroupItem}" ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Path=Display}"/>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
</ComboBoxItem>
</ComboBox>
Screenshot:

For those who still need this control, I've implemented a WPF version of my Silverlight control. It works only with view models and requires these view models to implement a special interface, but apart of this it's not difficult to use.
In WPF it looks like this:
You can download source code and sample application from here: WpfComboboxTreeview.zip

I had the same issue.
The easiest way to implement the behavior of a treeview in a combobox is to create a TextBox and stylize it to look like a combobox. Add an image next to it. The trick is to put the treeview in a popup control. Then, when the user clicks the textbox or the dropdown image you chose, the popup is displayed directly under the textbox.
Then, when the treeview item is selected, close the popup and place the text of the selected now in the textbox.
Here's an unstylized example:
XAML:
<Window x:Class="ComboBoxTreeView.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" MouseEnter="Window_MouseEnter">
<Grid Margin="15">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox Grid.Row="0" x:Name="header" Width="300" Height="30" PreviewMouseDown="header_PreviewMouseDown" HorizontalAlignment="Left" />
<Popup Grid.Row="1" x:Name="PopupTest" AllowsTransparency="True" IsOpen="False">
<TreeView x:Name="Tree1" Initialized="Tree1_Initialized" SelectedItemChanged="Tree1_SelectedItemChanged">
<TreeViewItem Header="Test1" x:Name="Tree1Item1">
<TreeViewItem Header="1test1" />
<TreeViewItem Header="2test2" />
</TreeViewItem>
<TreeViewItem Header="Test2" />
</TreeView>
</Popup>
</Grid>
</Window>
And here is the Code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ComboBoxTreeView
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_MouseEnter(object sender, MouseEventArgs e)
{
}
private void Tree1_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
var trv = sender as TreeView;
var trvItem = trv.SelectedItem as TreeViewItem;
if (trvItem.Items.Count != 0) return;
header.Text = trvItem.Header.ToString();
PopupTest.IsOpen = false;
}
private void Tree1_Initialized(object sender, EventArgs e)
{
var trv = sender as TreeView;
var trvItem = new TreeViewItem() { Header="Initialized item"};
var trvItemSel = trv.Items[1] as TreeViewItem;
trvItemSel.Items.Add(trvItem);
}
private void header_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
PopupTest.Placement = System.Windows.Controls.Primitives.PlacementMode.RelativePoint;
PopupTest.VerticalOffset = header.Height;
PopupTest.StaysOpen = true;
PopupTest.Height = Tree1.Height;
PopupTest.Width = header.Width;
PopupTest.IsOpen = true;
}
}
}

You might be able to use an event handler on the tree view to set the SelectedItem on the comboBox.
In order to do this you would need to set the Tag porperty of the tree view like so:
<TreeView Tag="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}" MouseDoubleClick="treeview_MouseDoubleClick" ItemsSource="{Binding Children}" x:Name="TheTree">
Now in the DoubleClick event you can get at the ComboBox:
private void treeview_MouseDoubleClick(object sender, RoutedEventArgs e)
{
try
{
TreeView tv = sender as TreeView;
if(tv == null)
return;
var cB = tv.Tag as ComboBox;
cB.SelectedItem = tv.SelectedItem;
}
catch (Exception e)
{
}
}
You will also need to override the way the comboBox Item is selecte, otherwise the whole TreeView will be selected as soon as you click on it.

This question is actually closely related to that one
So you would probably find this implementation helpful. This is a combobox with checkboxes inside, but you can get the idea on how to decouple the text in the box from the popup content with your tree.
It also demonstrates the idea that the IsSelected property should be on your model entities and then it is bound back to the checkbox Text property through the model. In other words, what you show in the combobox collapsed might be completely unrelated to the content... Well, maybe not completely, but in my app when a user selects several checkboxes in that combo I can show comma-separated in the top textbox, or I can show "Several options selected", or whatever.
HTH =)

It's an old topic but it can be useful to somebody.
Trying to do something similar with a combobox, I tried to use popup instead and it's working.
To turn it into a nice feature it needs a lot of tweaking.
<Expander Header="TestCS">
<Popup IsOpen="{Binding IsExpanded, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Expander}}}">
<TreeView ItemsSource="{Binding CSTree.CSChildren}">
<TreeView.Resources>
<HierarchicalDataTemplate ItemsSource="{Binding CSChildren}" DataType="{x:Type ViewModel:ObservableCS}">
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="16" Text="{Binding CSName}"></TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
</Popup>
</Expander>

I think you can foreach treeViewItems then add into combo 1by1.
and in each treeviewitem expand event, append its children into combobox.
however, set expandable item's height to looks like in one row, such as Height = 18d.
// == Append Item into combobox =================
TreeViewItem root = new TreeViewItem();
root.Header = "item 1";
TreeViewItem t1 = new TreeViewItem();
t1.Header = "Expanding...";
root.Items.Add(t1);
// ==============================================
// == root expandind event ==============================
root.Height = 18.00d;
TreeViewItem[] items = GetRootChildren(root.Tag);
foreach(TreeViewItem item in items)
{
combox1.Items.Add(item);
}
// ======================================================

There are two problems that you are having. The first is that when you select your one-and-only ComboBoxItem (the whole TreeView), that is what is returned into the ContentPresenter of the ComboBox's base ToggleButton. Simply making your ComboBox IsEditable will stop the whole TreeView from being put into the Content of the ComboBox but it still isn't selecting the item you chose in the TreeView. You'll have to use the SelectedItemChanged event in the TreeView to capture the selected item and then convert that into your 'SelectedItem'. Once you've selected the item and passed it to the ComboBox, set IsDropDownOpen to false.

Related

Return keyboard focus

I have an application where the main window contains a user control, and inside that user control are items stored in an ItemsControl. Each item can be removed by clicking an 'x' button.
The problem I am facing is that although the Keyboard focus is initially set to the user control, when you remove an item, focus is then transferred to the main window, instead of back to the user control?
Is there a way I can fix this without having to add code behind to manually store/retrieve/set focus after the click?
I have lots of these buttons within my application and I'm trying to avoid having to add code all over the place to manage returning the Focus.
I have created a very simple example to show the issue :
<UserControl x:Class="WpfApp28.MyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid Width="300">
<StackPanel>
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding}" />
<Button Content="x"
Width="20"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Click="Button_Click" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Grid>
</UserControl>
public partial class MyControl : UserControl
{
public MyControl()
{
InitializeComponent();
Focusable = true;
Loaded += MyControl_Loaded;
}
private void MyControl_Loaded(object sender, RoutedEventArgs e)
{
Keyboard.Focus(this);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (sender is FrameworkElement fe && fe.DataContext is string item)
{
(DataContext as ObservableCollection<string>).Remove(item);
}
}
}
<Window x:Class="WpfApp28.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp28"
Title="MainWindow" Height="450" Width="800">
<local:MyControl DataContext="{Binding Items}" />
public partial class MainWindow : Window
{
public ObservableCollection<string> Items { get; } = new ObservableCollection<string>();
public MainWindow()
{
Items.Add("hello");
Items.Add("there");
Items.Add("world");
DataContext = this;
InitializeComponent();
DispatcherTimer t = new DispatcherTimer();
t.Interval = TimeSpan.FromMilliseconds(250);
t.Tick += T_Tick;
t.Start();
}
private void T_Tick(object? sender, EventArgs e)
{
Title = Keyboard.FocusedElement?.GetType().ToString() ?? "NULL";
}
}
The reason that the keyboard focus moves to the hosting Window is obvious once you understand how WPF handles focus. It's important to know that WPF uses scopes in which the focus traverses the elements.
There can be multiple focus scopes allowing multiple elements to remain focused simultaneously.
By default, the hosting Window defines a focus scope. Since it is the only focus scope, it is global (the scope of the complete visual tree).
What happens in your code in short:
The Button receives the focus via mouse click
The click handler removes the clicked item and therefore the clicked Button from the visual tree
WPF moves focus back to the focus scope root, which is the MainWindow in your case
You have multiple options to prevent the focus from being moved back to the focus root. Some involve code-behind.
The following examples show how to move the focus back to the parent UserControl. But it could be any element as well:
You can configure the Button (the element that "steals" the current focus) to be not focusable. This only works if the UserControl is already focused:
<DataTemplate>
<Button Content="x"
Focusable="False" />
</DataTemplate>
You can introduce a new focus scope. Since you want the UserControl itself to be focused, you must choose the root element of the UserControl. You can achieve this by using the FocusManager helper class:
<UserControl>
<Grid x:Name="RootPanel"
FocusManager.IsFocusScope="True"
Width="300">
</Grid>
</UserControl>
You can of course register a Button.Click handler or preferably a routed command to move the focus back to the UserControl explicitly. A routed command can be more convenient in most cases. It allows to send a command parameter that makes the code-behind simpler.
Note, since Button.Click is a routed event, you can simply register a Button.Click event handler on the UserControl. This example uses the existing click handler that is used to remove the item from the ItemsControl:
UserControl.xaml
<DataTemplate>
<Button Content="x"
Click="OnButtonClick" />
</DataTemplate>
UserControl.xaml.cs
private void OnButtonClick(object sender, RoutedEventArgs)
{
/* Delete the item */
Keyboard.Focus(this);
}
Final suggested solution
To improve your code and handling of the UserControl you must definitely implement an ItemsSource dependency property and use a routed command to delete the items.
The following example uses the predefined ApplicationCommands.Delete routed command. You will notice how simple the code has become:
MyControl.xaml.cs
public partial class MyControl : UserControl
{
public IList ItemsSource
{
get => (IList)GetValue(ItemsSourceProperty);
set => SetValue(ItemsSourceProperty, value);
}
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(
"ItemsSource",
typeof(IList),
typeof(UserControl4), new PropertyMetadata(default));
public MyControl()
{
InitializeComponent();
this.Focusable = true;
}
public override void OnApplyTemplate()
=> Keyboard.Focus(this);
private void DeleteItemCommand_Executed(object sender, ExecutedRoutedEventArgs e)
=> this.ItemsSource.Remove(e.Parameter);
private void DeleteItemCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
=> e.CanExecute = this.ItemsSource.Contains(e.Parameter);
}
MyControl.xaml
<UserControl>
<UserControl.CommandBindings>
<CommandBinding Command="{x:Static ApplicationCommands.Delete}"
Executed="DeleteItemCommand_Executed"
CanExecute="DeleteItemCommand_CanExecute" />
</UserControl.CommandBindings>
<Grid x:Name="RootPanel"
FocusManager.IsFocusScope="True">
<StackPanel>
<ItemsControl ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=local:UserControl4}, Path=ItemsSource}"
>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding}" />
<Button Content="x"
Command="{x:Static ApplicationCommands.Delete}"
CommandParameter="{Binding}"
Width="20"
HorizontalAlignment="Right"
VerticalAlignment="Center" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Grid>
</UserControl>
MainWindow.xaml
<Window>
<MyControl ItemsSource="{Binding Items}" />
</Window>
Remarks
You should consider to use a ListBox instead of the pure ItemsControl.
ListBox is an extended ItemsControl. It will significantly improve performance and provides a ScrollViewer by default.

CollectionViewSource unselect selectedItem when clicking a group name

I have a listbox that has its itemSource bound to a collectionViewSource that is grouped and has 2 levels of groupings over the actual items:
<ListBox ItemsSource="{Binding Source={StaticResource myCVS}}" ItemTemplate="{StaticResource myItemsTemplate}" ItemContainerStyle="{StaticResource myItemsStyle}" SelectedItem="{Binding SelectedListItem}" >
<ListBox.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource HeaderStyle}" />
<GroupStyle ContainerStyle="{StaticResource SubHeaderStyle}" />
</ListBox.GroupStyle>
</ListBox>
With a CollectionViewSource bound to an ObservabeleCollection:
<CollectionViewSource x:Key="myCVS" Source="{Binding Path=myItemsToGroup}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="HeaderName" />
<PropertyGroupDescription PropertyName="SubHeaderName" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
the items in the ObservalbleCollection look like:
public class Items
{
public string GroupName;
public string SubGroupName;
public string ItemName;
}
This all works great i end up with:
Header1
|_SubHeader1
|_item1
|_item2
Header2
|_SubHeader2
|_item1
|_item2
The problem is if i click an item it becomes selected, and stays selected if I click on a header or subheader. If a header is clicked I would like to set the SelectedItem to null. I am using a command to remove the SelectedItem from the UI, but i don't want the command to execute if a header or subheader is being clicked only when a item is being clicked.
GroupStyles are not selectable, so of course your view model won't see a selection change happen.
To work around this, you can use some code behind. What you'll notice is if you click on the items in the ListBox, then ListBoxItem will set the MouseUp event's Handled property to true. If you click anywhere else on the ListBox, nothing handles the event. With that being said, you can set your selected item based on the state of Handled.
XAML:
<ListBox ItemsSource="{Binding Source={StaticResource myCVS}}"
ItemTemplate="{StaticResource myItemsTemplate}"
ItemContainerStyle="{StaticResource myItemsStyle}"
SelectedItem="{Binding SelectedListItem}"
MouseLeftButtonUp="ListBox_MouseLeftButtonUp">
Code-behind:
private void ListBox_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if(!e.Handled)
{
var lb = sender as ListBox;
lb.SelectedItem = null;
}
}
Addendum:
Clicking on an already selected item will set the SelectedItem to null. To prevent that, do this: instead of using MouseLeftButtonUp use MouseDown:
<ListBox ItemsSource="{Binding Source={StaticResource myCVS}}"
SelectedItem="{Binding SelectedListItem}"
MouseDown="ListBox_MouseLeftButtonUp">
Here is the state of my current application (GroupStyle's) don't get drawn properly, but the implementation is what's important here. If this doesn't do it for you, I would implement a pure MVVM approach.

Expander inside ListBox not showing content when expanded the first time from binding

I have a dialog window that contains a ListBox whose ItemTemplate contains an expander.
Its IsExpanded is bound to a property in the item view model. The ListBoxItem's IsSelected property is also bound to the IsExpanded property in the item view model object. And finally the SelectedItem property of the ListBox is bound to a property with the same name in the view model.
The problem here is that when setting up the view model before showing the dialog and setting it to the DataContext of the dialog, the item in the listbox gets selected as it should, the expander arrow shows that it is in the expanded state, but the content of the expander is not displayed.
If I set up the view model after showing the dialog, eg. in the Loaded handler of the dialog things work as expected. What is going on here, and what would be the best way to fix it?
The dialog window is defined as:
<Window x:Class="WpfApplication1.Dialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:WpfApplication1"
Title="Dialog" Height="300" Width="300">
<Grid>
<ListBox ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<Expander Header="Expander" x:Name="MyExpander" IsExpanded="{Binding IsExpanded, Mode=TwoWay}">
<Rectangle Width="100" Height="20" Fill="Red" />
</Expander>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsSelected" Value="{Binding IsExpanded, Mode=TwoWay}" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Grid>
And the ViewModel (implementation not included for the sake of brevity):
public interface IMyViewModel : INotifyPropertyChanged
{
object SelectedItem { get; set; }
ObservableCollection<IMyItemViewModel> Items { get; }
}
public interface IMyItemViewModel : INotifyPropertyChanged
{
bool IsExpanded { get; set; }
}
Then I have a simple main window with a button, and its Click handler is defined as:
private void Button_Click(object sender, RoutedEventArgs e)
{
MyViewModel vm = new MyViewModel();
MyItemViewModel item = new MyItemViewModel();
vm.Items.Add(item);
vm.SelectedItem = item;
Dialog dialog = new Dialog();
dialog.DataContext = vm;
dialog.ShowDialog();
}
When I run the application and click the button, the dialog shows up, the expander arrow indicates that it is in the expanded state, but its content is not displayed. Clicking on the expander collapses it, and clicking it again expands it, this time showing the content.
Putting the same code directly in the Main Window instead of a dialog however works as it is supposed to.
If I just do a Dispatcher.BeginInvoke(new Action(() => vm.SelectedItem = item); instead of setting it directly things also seem to work, but this feels a bit shaky.
What can be done to fix this problem?
Sounds like the content of the expander is not measured again after it is loaded, if the IsExpanded property is already set to true. Or to put it another way, the content is measured when it has still no actual size.
I suppose the easiest solution would be to just set the SelectedItem once the dialog has been loaded:
dialog.Loaded += (s, x) => vm.SelectedItem = item;

TabControl fails to create first tab when using data binding

I have a tab control which items source I databind to an observable collection. I use data templates to define the visual representation of the tab's headers and content.
When I add an item to the observable collection I get a tab header but no content. When I add a second item to the observable collection I get tab headers and content for both items. So first when the second item is added to the observable collection, the content for the first tab is created. Anyone knows if this is a bug or can explain why it happens? Is there a workaround? I tried using template selector with same result. Below is sample code to reproduce.
I tested this with both .NET 3.5 and 4.0.
XAML:
<Window x:Class="TabDemo.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel>
<Button Content="Add new tabitem" Click="OnAdd" />
<TabControl
ItemsSource="{Binding Path=Items}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</StackPanel>
</Window>
Code behind:
public partial class Window1
{
public Window1()
{
InitializeComponent();
Items = new ObservableCollection<int>();
DataContext = this;
}
public ObservableCollection<int> Items { get; set; }
private void OnAdd(object sender, RoutedEventArgs e)
{
Items.Add(_random.Next(100));
}
private readonly Random _random = new Random();
}
If you set SelectedIndex="0" on your TabControl, it will work around this issue. I believe this has to do with a bug coercing the SelectedIndex as items are added/removed.

How do I set the ZIndex of a Listbox Item on MouseEnter?

I have a different style for the items in my listbox on MouseOver which gives a slight zoom effect. This works nicely, but since the ZIndex is set in the order items are added to the ListBox, the zoomed item will be drawn behind the next item. I would like to set it so that the zoomed item is on top.
I've tried creating a MouseOver eventhandler, and setting the ZIndexProperty like this
private void ListItem_MouseEnter(object sender, MouseEventArgs e)
{
var grid = sender as Grid;
grid.SetValue(Canvas.ZIndexProperty, 5);
}
This doesn't work, and if I check the ZIndex without setting it at all, I always get 0 so it's like I'm not looking at the correct value. How can I modify the correct ZIndexProperty?
You don't include the relevant Xaml so it's hard for me to tell what event ListItem_MouseEnter is the handler for. If it's a handler for a ListBoxItem's MouseEnter event the sender will not be a Grid.
To change the ZIndex of a ListBoxItem on MouseOver the Xaml and code below will work:
Page.xaml
<UserControl x:Class="SilverlightApplication1.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<ListBox x:Name="ListBox1">
<ListBoxItem Content="Test 1" MouseEnter="ListBoxItem_MouseEnter" />
<ListBoxItem Content="Test 2" MouseEnter="ListBoxItem_MouseEnter" />
<ListBoxItem Content="Test 3" MouseEnter="ListBoxItem_MouseEnter" />
<ListBoxItem Content="Test 4" MouseEnter="ListBoxItem_MouseEnter" />
</ListBox>
</Grid>
</UserControl>
Page.xaml.cs:
using System;
using System.Windows.Controls;
using System.Windows.Input;
namespace SilverlightApplication1
{
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
}
private void ListBoxItem_MouseEnter(object sender, MouseEventArgs e)
{
ListBoxItem listBoxItem = (ListBoxItem)sender;
listBoxItem.SetValue(Canvas.ZIndexProperty, 5);
}
}
}
Notice the event handler is for each ListBoxItem's MouseEnter event meaning the sender is a ListBoxItem.
The ListBoxItem_MouseEnter method changes the Zindex to 5 on MouseEnter, verified using Silverlight Spy.

Resources