ScrollViewer+ItemsControl vs. ListView

One of my most recent tasks at work was determining the cause of slow performance in one part of an application and coming up with a fix (if possible).  We tracked the source of the problem down to a use of ItemsControl inside a ScrollViewer.  Because the ItemsControl instance was trying to display hundreds of complex items, it took a noticeably long time to load.  This turns out to be a known issue, with a few possible solutions.  Simply changing the ItemsPanelTemplate of the ItemsControl instance to contain a VirtualizingStackPanel didn’t fix our performance problem.

What did resolve our performance issue was replacing the ScrollViewer and ItemsControl combination with a ListView.  The list of what we changed includes:

  • Giving the ListView the same name as the ItemsControl.
  • Giving the ListView the same ItemsSource as the ItemsControl.
  • Update the ItemsPanelTemplate of the ListView to use VirtualizingStackPanel.
  • Set HorizontalScrollBarVisibility to “Disabled”.
  • Bound the Visibility property of the ListView to a Converter.
  • Update the ItemContainerStyle with a ListViewItem style that sets the HighlightBrushKey and ControlBrushKey to be transparent.

Note: The last of those steps does override those styles for the entire application, so it may be best to skip it unless it doesn’t negatively impact the look-and-feel of the rest of your application.

The changes we made reduced the load time from around 20 seconds down to less than 2 seconds for 400 items.

The tradeoff in moving to a ListView (with VirtualizingStackPanel) from ScrollViewer+ItemsControl is scrolling speed.  Scrolling through 400 items does go more slowly, but it’s preferable to waiting as long as we did just to see the data.

Implementing Mouse Hover in WPF

We’ve spent the past couple of weeks at work giving ourselves a crash course in Windows Presentation Foundation (WPF) and LINQ.  I’m working on a code example that will switch the datatemplate in a list item when the mouse hovers over it.  Unfortunately, WPF has no MouseHover event like Windows Forms does.  The usual googling didn’t cough up a ready-made answer.  Some hacking on one example did reveal a half-answer (not ideal, but at least a start).

First, I set the ToolTip property of the element I used to organize my data (in this case, a StackPanel).  Next, I added a ToolTipOpening event for the StackPanel.  Here’s the code for StackPanel_ToolTipOpening:

private void StackPanel_ToolTipOpening(object sender, ToolTipEventArgs e)
{
e.Handled = true;
ContentPresenter presenter = (ContentPresenter)(((Border)((StackPanel)e.Source).Parent).TemplatedParent);
presenter.ContentTemplate = this.FindResource("Template2") as DataTemplate;
}

The result: instead of a tooltip displaying when you hover over a listbox row, the standard datatemplate is replaced with an expanded one that displays more information.  This approach definitely has flaws.  Beyond being a hack, there’s no way to set how long you can hover before the templates switch.

Switching from an expanded datatemplate back to a standard one involved a bit less work.  I added a MouseLeave event to the expanded template.  Here’s the code for the event:

private void StackPanel_MouseLeave(object sender, MouseEventArgs e)
{
ContentPresenter presenter = (ContentPresenter)(((Border)((StackPanel)e.Source).Parent).TemplatedParent);
presenter.ContentTemplate = this.FindResource("ScriptLine") as DataTemplate;
}

So once the mouse moves out of the listbox item with the expanded template, it switches back to the standard template.  Not an ideal solution, but it works.

This link started me down the path to finding a solution (for reference).