When I expand items in my treeview so that scrolling is necessary, a scrollbar appears. However, it doesn\'t scroll down for the newly expanded branch of items - they get cr
I modified Jared's answer in combination with the strategy from here: https://stackoverflow.com/a/42238409/2477582
The main advantage is that there aren't n calls of BringIntoView() for n childs. There is only one call of BringIntoView for an area that covers all of the child's heights.
Additionally, the purpose of the referred topic is realized as well. But this part may be removed, if unwanted.
/// Prevents automatic horizontal scrolling, while preserving automatic vertical scrolling and other side effects
/// Source: https://stackoverflow.com/a/42238409/2477582
private void TreeViewItem_RequestBringIntoView(object sender, RequestBringIntoViewEventArgs e)
{
// Ignore re-entrant calls
if (m_SuppressRequestBringIntoView)
return;
// Cancel the current scroll attempt
e.Handled = true;
// Call BringIntoView using a rectangle that extends into "negative space" to the left of our
// actual control. This allows the vertical scrolling behaviour to operate without adversely
// affecting the current horizontal scroll position.
m_SuppressRequestBringIntoView = true;
try
{
TreeViewItem tvi = sender as TreeViewItem;
if (tvi != null)
{
// take care of children
int ll_ChildCount = VisualTreeHelper.GetChildrenCount(tvi);
double ll_Height = tvi.ActualHeight;
if (ll_ChildCount > 0)
{
FrameworkElement ll_LastChild = VisualTreeHelper.GetChild(tvi, ll_ChildCount - 1) as FrameworkElement;
ll_Height += ll_ChildCount * ll_LastChild.ActualHeight;
}
Rect newTargetRect = new Rect(-1000, 0, tvi.ActualWidth + 1000, ll_Height);
tvi.BringIntoView(newTargetRect);
}
}
catch (Exception ex)
{
m_Log.Debug("Error in TreeViewItem_RequestBringIntoView: " + ex.ToString());
}
m_SuppressRequestBringIntoView = false;
}
The above solution works together with this:
/// Correctly handle programmatically selected items (needed due to the custom implementation of TreeViewItem_RequestBringIntoView)
/// Source: https://stackoverflow.com/a/42238409/2477582
private void TreeViewItem_Selected(object sender, RoutedEventArgs e)
{
((TreeViewItem)sender).BringIntoView();
e.Handled = true;
}
This part takes care of toggling the elements at each click:
/// Support for single click toggle
private void TreeViewItem_MouseUp(object sender, MouseButtonEventArgs e)
{
TreeViewItem tvi = null;
// Source may be TreeViewItem directly, or be a ContentPresenter
if (e.Source is TreeViewItem)
{
tvi = e.Source as TreeViewItem;
}
else if (e.Source is ContentPresenter)
{
tvi = (e.Source as ContentPresenter).TemplatedParent as TreeViewItem;
}
if (tvi == null || e.Handled) return;
tvi.IsExpanded = !tvi.IsExpanded;
e.Handled = true;
}
Finally the XAML part: