If virtualizing is enabled in TreeView
with items having various sizes, multiple problems appear:
Vertical scroll bar changes its size randomly and doesn't remember sizes of elements after viewing the whole tree. Scrolling with mouse is hard.
After some scrolling up and down, ArgumentNullException
is thrown from the framework code.
Reproduciing is simple: create a new WPF application, then put this code into MainWindow.xaml
<Window x:Class="VirtualTreeView.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="800" Width="400" Left="0" Top="0" DataContext="{Binding RelativeSource={RelativeSource Self}}"> <Grid> <TreeView x:Name="tvwItems" ItemsSource="{Binding Items}" VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.VirtualizationMode="Recycling"> <TreeView.ItemTemplate> <DataTemplate> <Border Height="{Binding Height}" Width="{Binding Height}" BorderThickness="1" Background="DarkGray" BorderBrush="DarkBlue"/> </DataTemplate> </TreeView.ItemTemplate> </TreeView> </Grid> </Window>
and this code into MainWindow.xaml.cs
using System.Collections.ObjectModel; using System.Linq; namespace VirtualTreeView { public partial class MainWindow { public ObservableCollection<Item> Items { get; set; } public MainWindow () { Items = new ObservableCollection<Item>(Enumerable.Range(0, 20).Select(i => new Item { Height = i*20, })); InitializeComponent(); } } public class Item { public double Height { get; set; } } }
When application is ran, move mouse cursor into a treeview, scroll to the bottom using mouse wheel, then scroll to the top, then start scrolling down again. Somewhere in the middle the following exception is thrown:
System.ArgumentNullException was unhandled HResult=-2147467261 Message=Value cannot be null. Parameter name: element Source=PresentationCore ParamName=element StackTrace: at MS.Internal.Media.VisualTreeUtils.AsNonNullVisual(DependencyObject element, Visual& visual, Visual3D& visual3D) at System.Windows.Media.VisualTreeHelper.GetParent(DependencyObject reference) at System.Windows.Controls.VirtualizingStackPanel.FindScrollOffset(Visual v) at System.Windows.Controls.VirtualizingStackPanel.OnAnchorOperation(Boolean isAnchorOperationPending) at System.Windows.Controls.VirtualizingStackPanel.OnAnchorOperation() at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler) at System.Windows.Threading.DispatcherOperation.InvokeImpl() at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Windows.Threading.DispatcherOperation.Invoke() at System.Windows.Threading.Dispatcher.ProcessQueue() at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler) at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs) at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam) at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg) at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame) at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame) at System.Windows.Threading.Dispatcher.Run() at System.Windows.Application.RunDispatcher(Object ignore) at System.Windows.Application.RunInternal(Window window) at System.Windows.Application.Run(Window window) at System.Windows.Application.Run() at VirtualTreeView.App.Main() in d:\Docs\Projects\_Try\VirtualTreeView\obj\Debug\App.g.cs:line 0 at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart()
You can also see that exception is not the only problem. When scrolling up and down, scroll bar constantly changes its size. (The same problem doesn't appear in ListBox
which can't predict size, but remembers total height after viewing the whole list.)
Question: How to make the scroll bar behave properly and get rid of the exception? (I don't mind links to alternative TreeView controls or maybe virtualizing panels which support this scenario.)
To make the link more prominent, I am posting it in an answer too. It looks like a bug is within the framework code and there are no workarounds found yet. I have reported the bug on Microsoft Connect:
Microsoft Connect: Scrolling in virtualized WPF TreeView is very unstable
There is also a maybe related bug which was posted in the comments by @sixlettervariables:
Microsoft Connect: WPF application freezes while scrolling the TreeView under specific conditions
If you can reproduce the bugs, please vote them up.
As of .NET 5 this issue still exists in WPF, and Microsoft has retired Microsoft Connect so it's unclear if this is even on their radar anymore. I encountered the same issue and stumbled across a fix that worked for me purely by accident. Essentially it's just doing the same thing the TreeView should be doing, using a HierarchichalDataTemplate to render each node, but where the built-in TreeView crashes while scrolling, this version doesn't (on the tree of items in my case).
<DockPanel> <DockPanel.Resources> <HierarchicalDataTemplate DataType="{x:Type src:Item}" ItemsSource="{Binding Path=Children}"> <TextBlock Text"{Binding}"/> </HierarchicalDataTemplate> </DockPanel.Resources> <TreeView x:Name="tvwItems" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling" ItemsSource="{Binding Items}"> </TreeView> </DockPanel>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With