Setting DataGrid ItemsSource causes XamlParseException - wpf

so I have a problem with an XAML file I'm using; I'm trying to use a DataGrid to add a table view of the properties for an element the user selects. How I'm currently attempting to do this is that I have a list containing the appropriate pairs that gets populated on user click, and then the ItemsSource is set to that list. I have tried changing the details of this implementation (binding the ItemsSource without a reference to the datagrid itself, etc, but sooner or later they all seem to hit the same error)
The weird thing (to me) is that after a few clicks on different elements (and hitting 'continue' when the exception pops up) the grid does populate with data, although it often seems to "freeze" (showing the same data for a few elements before finally refreshing a couple of elements later, no exceptions are thrown, but the behaviour is definitely inconsistent)
.xaml.cs
// ParameterPair is a custom class that contains 2 string fields (name, value)
public List<ParameterPair> AllParameters { get; private set; } = new List<ParameterPair>();
// called (only) when a new element is click
// ... code to populate AllParameters here
// definitely populates properly, checked through debugging
this.dGrid.ItemsSource = AllParameters;
.xaml
<Page ...>
<Grid HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TabControl>
<TabItem Header="Add Constraint">
<Grid Name="loginBlock" Grid.Row="0">
<GroupBox Header="Properties"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Margin="10, 10, 10, 0">
<StackPanel>
<controls:DataGrid x:Name="dGrid"
Height="300" Margin="12"
AutoGenerateColumns="true"
ItemsSource="{Binding}"
/>
</StackPanel>
</GroupBox>
</Grid>
</TabItem>
<TabItem Header="Manage Constraints" />
</TabControl>
</Grid>
</Page>

The error doesn't seem to be from your databinding, but from the xaml markup somewhere.
Your GroupBox doesn't seem to have closing brackets.
And is this a custom DataGrid? Since it's referenced as "controls:DataGrid" unlike your other controls. There might be something wrong in its markup.

Okay, so I fixed it. Turns out AutoGenerateColumns="true" was the culprit. I came upon this thread in my frustration, and tried manually setting the columns, which seems to work perfectly fine, just binding the columns to the appropriate fields in the class being used for the list.
<DataGrid x:Name="dGrid"
Height="300" Margin="12"
AutoGenerateColumns="false"
ItemsSource="{Binding}"
>
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
<DataGridTextColumn Header="Value" Binding="{Binding Value}" />
</DataGrid.Columns>
</DataGrid>
P.S. I will avoid choosing this as my answer as it is largely a workaround, hopefully someone more experienced will come and give a more thorough and concise solution (maybe myself later on in this project...)

Related

ListBox inside ListBox, how do I know which button is clicked?

I have two ListBoxes, one inside another. And both ListBoxes will have items dynamically added into them upon user request.
Each time a button (not shown in the below code snippet) is clicked, a new item is added to the listbox. Each new item includes a new listbox and others.
And I have buttons inside the inner listbox, one for each list item of the inner listbox.
With DataContext, I can find the data binded to the inner list item, and make changes to it, so that changes are reflected on the proper list item.
However, I also need to make changes to the data binded to the outer list item, which corresponds to the button. How can I know which one it is?
I have came up with a solution, which I believe it not elegant enough. By making changes to the model, I can have each inner data holds a reference to the outer data, so that I can find the data binded to the outer list item. This doesn't seem like a proper solution though. Do you have any suggestions?
Below is code snippet of the xaml. I've simplified it, hope it's easy to understand. I feel you don't have to read the whole code.
<ListBox Name="QuestionsListBox" HorizontalAlignment="Stretch" ItemContainerStyle="{StaticResource ListItem}" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBox Text="{Binding Question, Mode=TwoWay}" Grid.Row="0" HorizontalAlignment="Stretch" TextWrapping="Wrap"/>
<ListBox Name="ChoicesListBox" ItemsSource="{Binding Choices}" Grid.Row="1" HorizontalAlignment="Stretch" ItemContainerStyle="{StaticResource ListItem}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Click="ChoiceAddButton_Click" Height="72" Width="72" HorizontalAlignment="Left" BorderBrush="Transparent">
<Button.Background>
<ImageBrush ImageSource="/Images/choices.add.png" Stretch="Fill" />
</Button.Background>
</Button>
<TextBox Text="{Binding Value, Mode=TwoWay}" HorizontalAlignment="Stretch" Grid.Column="1" Margin="-20,0" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Why not just use QuestionsListBox.DataContext inside ChoiceAddButton_Click directly? You have a direct way to reference the outer ListBox from your code behind since you've given it a name, and DataContext is an accessible property.
private void ChoiceAddButton_Click(object sender, RoutedEventArgs e)
{
...
var outerLBDataContext= QuestionsListBox.DataContext;
...
}
This works fine for me in a demo solution using your provided XAML.
Edit 2:
Sorry, wasn't thinking. The Button's DataContext will be a Choice, not the Choices collection.
Your inner ListBox's DataContext is not a Question, it's Choices. Your outer TextBox has Question.Question as its DataContext. Binding Text or ItemsSource makes the DataContext point to the binding target. Here is a bit of tricky XAML to sneak in a DataContext reference.
Add an ElementName to your outer TextBox:
<TextBox Text="{Binding Question, Mode=TwoWay}" Grid.Row="0" HorizontalAlignment="Stretch" TextWrapping="Wrap" ElementName="questionTextBox"/>
Now, add a hidden TextBlock inside your inner ListBox:
<ListBox Name="ChoicesListBox" ItemsSource="{Binding Choices}" Grid.Row="1" HorizontalAlignment="Stretch" ItemContainerStyle="{StaticResource ListItem}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Click="ChoiceAddButton_Click" Height="72" Width="72" HorizontalAlignment="Left" BorderBrush="Transparent">
<Button.Background>
<ImageBrush ImageSource="/Images/choices.add.png" Stretch="Fill" />
</Button.Background>
</Button>
<TextBox Text="{Binding Value, Mode=TwoWay}" HorizontalAlignment="Stretch" Grid.Column="1" Margin="-20,0" />
<TextBlock Name="hiddenTextBlock" Visibility="Collapsed" DataContext="{Binding ElementName=questionTextBox, Path=DataContext}"
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Finally, inside your event handler, you can navigate around the tree to get that reference:
private void ChoiceAddButton_Click(object sender, RoutedEventArgs e)
{
Button btn = sender as Button;
if(btn == null) return; //won't happen when this method handles the event
Grid g = btn.Parent as Grid;
if(g!=null) // also unlikely to fail
{
TextBlock tb = g.FindName("hiddenTextBlock") as TextBlock;
if(tb!=null) // also unlikely to fail, but never hurts to be cautious
{
var currentQuestion = tb.DataContext;
// now you've got the DC you want
}
}
}
I'd like to note that this isn't really an elegant solution. It is an all UI solution, however, which could be a useful thing. But better design would be to include Parent references in your Choice and ChoiceList (or whatever they're called) classes and use that. Then it would be as simple as calling btn.DataContext.Parent.Parent with appropriate type conversions. This way your code becomes easier to read and maintain.
You could add an event to your inner model that your containing datamodel subscribes to before adding it to the 'Choices' collection and pass the relevant information that way.
Is this necessary to use the Button control in your solution ??
If not fixed, then you can use the "Image control" as specified below <Image Source="/Images/choices.add.png" Height="72" Width="72" HorizontalAlignment="Left" Stretch="Fill"/>
If you use the Image control then in combination with this you can add the selection changed event to inner list box ( ChoicesListBox). Then in the Handler you can get the item selected as it comes as parameter with the selection changed event(SelectionChangedEventArgs).
Modify the List box and add the Selection changed event handler as below
<ListBox Name="ChoicesListBox" ItemsSource="{Binding Choices}" Grid.Row="1" HorizontalAlignment="Stretch" ItemContainerStyle="{StaticResource ListItem}" SelectionChanged="Items_SelectionChanged">
in page.xaml.cs you can add the handler and access the item as follows
private void Items_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems[0] != null)
{
//Please use the casting to the Choices items type to make use.
var temp = (ChoicesItemViewModel)e.AddedItems[0];
}
}

How come I can only have one instance of a Silverlight UserControl per page?

Its pretty lame, but I tried adding two UserControl's to my Silverlight Page, and I get an exception telling me (with extensive digging) that the same control name has been used to the visual tree twice. So the controls inside my UserControl are named, so therefore I can include only one of this UserControl into the Page at a time. Is this true, or am I not realizing something? Has Microsoft truly given up on code-reuse? This is very lame.
Edits
For people who come here, I was getting this a System.Resources.MissingManifestResourceException exception. It took some time to figure out that the problem was ambiguous names in the visual tree. Hopefully this helps you. Below is the full exception text.
Further Edits
Here is my XAML:
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock x:Name="HeaderText"
res:Strings.Assignment="Text=MachiningView_Name"/>
<sdk:TabControl Grid.Row="2">
<sdk:TabItem Header="Projects">
<ScrollViewer>
<Grid>
<controls:Organizer Margin="4" ItemsSource="{Binding ProjectSummaries}" Height="24" VerticalAlignment="Top">
<controls:Organizer.GroupDescriptions>
<controls:OrganizerGroupDescription res:Strings.Assignment="Text=NoGroupingText" IsDefault="True" />
<controls:OrganizerGroupDescription res:Strings.Assignment="Text=GroupOwnerEmailText">
<controls:OrganizerGroupDescription.GroupDescription>
<helpers:OwnerEmailGroupDescription />
</controls:OrganizerGroupDescription.GroupDescription>
</controls:OrganizerGroupDescription>
<controls:OrganizerGroupDescription res:Strings.Assignment="Text=GroupStoreNumberText">
<controls:OrganizerGroupDescription.GroupDescription>
<helpers:StoreNumberGroupDescription />
</controls:OrganizerGroupDescription.GroupDescription>
</controls:OrganizerGroupDescription>
</controls:Organizer.GroupDescriptions>
</controls:Organizer>
</Grid>
</ScrollViewer>
</sdk:TabItem>
<sdk:TabItem Header="Machine Queues">
<ScrollViewer>
<Grid>
<controls:Organizer Margin="4" ItemsSource="{Binding ProjectSummaries}" Height="24" VerticalAlignment="Top">
<controls:Organizer.GroupDescriptions>
<controls:OrganizerGroupDescription res:Strings.Assignment="Text=NoGroupingText" IsDefault="True" />
<controls:OrganizerGroupDescription res:Strings.Assignment="Text=GroupOwnerEmailText">
<controls:OrganizerGroupDescription.GroupDescription>
<helpers:OwnerEmailGroupDescription />
</controls:OrganizerGroupDescription.GroupDescription>
</controls:OrganizerGroupDescription>
<controls:OrganizerGroupDescription res:Strings.Assignment="Text=GroupStoreNumberText">
<controls:OrganizerGroupDescription.GroupDescription>
<helpers:StoreNumberGroupDescription />
</controls:OrganizerGroupDescription.GroupDescription>
</controls:OrganizerGroupDescription>
</controls:Organizer.GroupDescriptions>
</controls:Organizer>
</Grid>
</ScrollViewer>
</sdk:TabItem>
</sdk:TabControl>
</Grid>
And here is my user control's XAML:
<StackPanel Orientation="Horizontal" DataContext="{Binding ElementName=UserControl}">
<sdk:Label Content="Page:" VerticalAlignment="Center" Margin="0,0,5,0"/>
<sdk:DataPager Name="_projectSummariesPager"
Margin="0,0,5,0"
DisplayMode="FirstLastPreviousNextNumeric"
Source="{Binding Path=ItemsSource}"
PageSize="10"/>
<ComboBox Name="_itemPerPageCombo"
Margin="0,0,5,0"
SelectionChanged="_itemPerPageCombo_SelectionChanged"
SelectedItem="{Binding Path=SelectedPageSize, Mode=TwoWay}"
SelectedValuePath="Value"
ItemsSource="{Binding Path=PageSizes}"/>
<ComboBox Name="_groupDescription"
Margin="0,0,5,0"
SelectionChanged="_groupDescription_SelectionChanged"
SelectedItem="{Binding Path=SelectedGroupDescription, Mode=TwoWay}"
ItemsSource="{Binding Path=GroupDescriptions}"/>
</StackPanel>
Names given to elements in Xaml need to be unique within the namescope. Each execution of LoadComponent creates a new namescope. Hence the names within the UserControl will not conflict in the visual tree when multiple instances of the control were used.
So the answer to question as it stands right now is: because you are doing something wrong.
What the "something" is is unclear right now. Perhaps if you included your xaml in the question we can help you.
Edit
So reading between the lines this is what I'm guessing you are doing. You have a UserControl that has a number for properties and you want controls within the UserControl to bind to these properties so you are doing this:-
<StackPanel Orientation="Horizontal" DataContext="{Binding ElementName=UserControl}">
This would indicate that you have added Name="UserControl" to the <UserControl.. element at the top of its xaml.
I can't quite find a way to reproduce your problem but I am aware of problems with earlier versions of SL where this approach is a problem. Personally I think its better to avoid setting properties that really belong to the external consumer of the component (its up to the page that is using you UserControl what its name is and whether it should have name at all).
Hence my approach to solve this "Bind to the UserControl itself" sort of Problem:-
<StackPanel Orientation="Horizontal" DataContext="{Binding ElementName=LayoutRoot.Parent}">
where LayoutRoot is the name of the top level Grid which is the root of the UserControl content. This still binds to the UserControl itself via the Grid's Parent property. However this does not require a name to be added to the UserControl itself in its own xaml.
When you add the UserControl, make sure to assign it a unique name, ie:
<Page ...
<StackPanel>
<local:YourUserControl x:Name="Foo" />
<!-- Make sure not to duplicate x:Name/Name here! -->
<local:YourUserControl x:Name="Bar" />
</StackPanel>
</Page>

Spanning a Record Over Multiple Rows in WPF Toolkit's DataGrid

Is it possible to style WPF Toolkit's DataGrid so a data record can span multiple rows. Example screen shot from a commercial control.
Thanks,
Ben
It is not possible with the toolkit DataGrid or GridView for a ListView, no.
However you may have luck with your own implementation, as I recently discovered you can use GridViewHeaderRowPresenter (MSDN reference), set the Columns property to the columns you want: that will give you a header row.
Then you can use GridViewRowPresenter (MSDN reference), attach it to the same Columns collection and voila, your columns in the rows and header will be linked (resize the header, the columns change).
See here for a good example:
http://msdn.microsoft.com/en-us/library/ms752313.aspx
In order to get the stacked effect, you could create a ListView or ListBox, and for each item you'd output a vertically-stacked pair of GridViewRowPresenter controls, each bound to a separate columns collection. Then in your own custom header (just above the control) you'd do the same thing with a pair of GridViewHeaderRowPresenter controls.
You could then add any other bits you'd like as well, for example the text/label that they have in your example screenshot.
No reason why this shouldn't work. It's not a pre-built solution but is possible with clean coding, it's not a hack, and you have complete control over how it looks and works! Adding sorting and so on is fairly easy too, MSDN has an example for that too.
Hope that helps - any more questions on the details of this please add a comment here!
It looks as though the control in that screenshot is creating the illusion of row-span by dividing the cells in every column to the right of the picture into multiple rows. Perhaps you could achieve the row-span effect you are looking for in the same way.
<tk:DataGrid AutoGenerateColumns="False">
<tk:DataGrid.Columns>
<tk:DataGridTextColumn Header="ID" Binding="{Binding ID}" />
<tk:DataGridTemplateColumn Header="Photo">
<tk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding Photo}" />
</DataTemplate>
</tk:DataGridTemplateColumn.CellTemplate>
</tk:DataGridTemplateColumn>
<tk:DataGridTemplateColumn>
<tk:DataGridTemplateColumn.Header>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0">FirstName</TextBlock>
<TextBlock Grid.Row="1">LastName</TextBlock>
</Grid>
</tk:DataGridTemplateColumn.Header>
<tk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding FirstName}" />
<TextBlock Grid.Row="1" Text="{Binding LastName}" />
</Grid>
</DataTemplate>
</tk:DataGridTemplateColumn.CellTemplate>
</tk:DataGridTemplateColumn>
</tk:DataGrid.Columns>
</tk:DataGrid>

What Does this MSDN Sample Code Do? - ItemsControl.ItemTemplate

This is a XAML code sample taken from the MSDN library article for the ItemsControl.ItemTemplate property:
<ListBox Width="400" Margin="10" ItemsSource="{Binding Source={StaticResource myTodoList}}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=TaskName}" />
<TextBlock Text="{Binding Path=Description}"/>
<TextBlock Text="{Binding Path=Priority}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I'm looking for an explanation of the usage of the <StackPanel> element is this example.
->
Where is this panel going to exist in the ListBox?
What is its purpose in the ItemTemplate?
Can any System.Windows.Controls.Panel be used in its place, specifically a Grid?
How would I go about using a <Grid> element as the template for each item in the ListBox?
Here is the concept I am going for:
http://img151.imageshack.us/img151/7960/graphconcept.png
I have drawn the graph using a <Path> element, and there are no problems there.
I am working on the labels for the axies, and I am experimenting with the use of a <Grid> element in the ItemTemplate - but I have no idea how the grid is supposed to function in this context, and MSDN says nothing about the panel in their sample code.
My XAML for the Y-axis labels currently looks like this:
<ListBox Background="Transparent" BorderThickness="0" ItemsSource="{Binding Path=GraphLabelYData}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="{Binding Path=GraphLabelSpacing}" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="{Binding ElementName=GraphLabelYData, Path=GraphLabelMarkerLength}" />
</Grid.ColumnDefinitions>
<TextBlock HorizontalAlignment="Right" VerticalAlignment="Bottom" Text="{Binding Path=GraphLabelTag}" />
<Rectangle Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Stroke="Black" Fill="Black" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Does this look correct? Nothing shows up at run-time, but I want to make sure the XAML is modeled correctly before I start debugging the data-bindings and the code-behind.
"Where is this panel going to exist in the ListBox?" - The listbox will make one copy of it for each list item, i.e. one for each element in the myTodoList collection. So within each list item, you'll have the three labels stacked one above the other.
"What is its purpose in the ItemTemplate?" - To make it possible to show more than one control for each element in the ItemsSource. ItemTemplate, like many things in WPF, can only take one child element, so if you want multiple children, you need to specify how you want them laid out, and you do that by adding a panel (StackPanel in this case).
"Can any System.Windows.Controls.Panel be used in its place, specifically a Grid?" - You bet.
"How would I go about using a <Grid> element as the template for each item in the ListBox?" - The same way you would use a Grid anywhere else. It's no different; it's just that ItemsControl (and its descendant, ListBox) will create multiple instances of your Grid. Note, though, that inside the ItemTemplate, your DataContext will be the current list item, and therefore your {Binding}s will be relative to that list item (unless you specify otherwise with e.g. ElementName).
"Does this look correct?" - This really should be posted as a separate question, as it's unrelated to the questions about the MSDN sample, and I'm not even sure what you're trying to do. But I'll try to answer: I suspect something is wrong, because you're using the name "GraphLabelYData" two different ways. In the ColumnDefinition, as far as I can tell, you're treating GraphLabelYData as the name of a XAML element (i.e. you're looking for another control in the window/page/UserControl with Name="GraphLabelYData" or x:Name="GraphLabelYData", and reading that control's GraphLabelMarkerLength property); but in the TextBlock, you're treating GraphLabelYData as the name of a property on the current collection item. I suspect one of those isn't right.

WPF - Hovering over one Element shows content in another Element

I would like to achieve an affect whereby I can hover over a Button and have a TextBlock update its content (via binding). To complicate matters, The Button is one of many buttons defined in an ItemsControl/DataTemplate. The TextBlock is outside the scope of the ItemsControl.
Some simplified markup of the problem is as follows:
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<ItemsControl Grid.Row="0">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Title}"
Command="{Binding Command}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock x:Name="TitleTextBox" Grid.Row="1" />
</Grid>
Say in this example, I may want to bind the "Title" property of the data item to the TextBlock's "Text" property.
I assume I want to be tapping into the IsMouseOver of the button, but I can't seem to get it hooked up properly.
I don't believe you're going to be able to accomplish this without some code... however, you don't need to use codebehind. A "behavior" would work just fine for this (either an old school attached behavior, or a more modern Blend Behavior). Here's what the modified markup might look like using an attached behavior:
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<ItemsControl x:Name="Buttons" Grid.Row="0" ext:Hover.TrackChildItems="true">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Title}"
Command="{Binding Command}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock x:Name="TitleTextBox"
Grid.Row="1"
Text="{Binding ElementName=Buttons, Path=ext:Hover.Item.Content}" />
</Grid>
Here the attached behavor "Hover.TrackChildItems" is used to watch for the appropriate mouse events, and sets the readonly "Hover.Item" attached property to the control being hovered over. Writing the behavior should be simple enough, and is left to you.
Edit: To set up the event handlers for the items, the first thing to do is simple and obvious: iterate over the items in the Items property and add the handlers.
Mouse.AddMouseEnter(item, OnMouseEnter);
This works fine for static content, but dynamic (added and removed at runtime) content will be missed by this. So, next you must track changes to the Items property.
((INotifyCollectionChanged)Items).CollectionChanged += OnItemsChanged;
Add or remove the mouse event handlers as appropriate when items are added and removed in the CollectionChanged handler.
There's also another solution. Create a new HoverTrackingItemsControl for this, derived from ItemsControl. In this control override the GetContainerForItemOverride method to return a new HoverTrackingItem, which handles MouseEnter/MouseLeave to notify the parent HoverTrackingItemsControl. This solution is probably easier to implement, though it does require a specialized control, while the Behavior solution is more generic and can be used with any ItemsControl type (ItemsControl, ListBox, ComboBox, etc.).

Resources