Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF ListBox scrolls to top when I change status message or show wait screen

I'm developing an opensource application named Media Assistant. I used a ListBox to show the library. ItemsSource is bound to a list of LibraryItem. Here is the XALM.

<ListBox Name="Tree" DockPanel.Dock="Top" 
    ItemsSource="{Binding DataSource.OrderedLibraryItems}" 
    Background="{StaticResource LibraryBackground}"
    Width="220" HorizontalAlignment="Left"
    BorderThickness="0"
    VirtualizingStackPanel.IsVirtualizing="True"
    VirtualizingStackPanel.VirtualizationMode="Standard"
    ScrollViewer.IsDeferredScrollingEnabled="True"
    ItemTemplate="{StaticResource ListLibraryItemTemplate}"
    SelectionMode="Single"
    MouseDoubleClick="HandleMouseDoubleClick"
/>

The problem is when I show any status message at the bottom of my window from a thread by using Dispatcher.

Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background,new ParameterizedThreadStart(action), state);

The ListBox scrolls to at the top. If I don't show any status message then it works just fine. The datacontext or list items or focus has not been changed. I could not found any reason why it's doing that. It happens when I display any wait screen which is a non modal window. I could not recreate it in a different project. Here is the source code of Media Assistant. You can easily re-create it by un-commenting the return statement of method SetStatusMessage at BackgroundScanner class.

like image 383
user904627 Avatar asked Nov 04 '22 16:11

user904627


1 Answers

I found the reason behind this, so the solution. I used a DockPanel to layout my UI. I put my status bar at the bottom, the ListBox on the Left and other items are on middle and top. There is a TextBlock in my StatusBar which has width and Height set to Auto. So, when I changed text of my StatusBar TextBlock it's width and height gets recalculated and It's parent's recalculates it's layout. Hence the ListBox gets invoked to Measures and Arrange. Even though it's size does not gets changed it resets it's scroll position to top. It happens only if I use ScrollViewer.CanContentScroll="True" at the ListBox. By default it is True. So, even though I did not set this value It was resetting the scroll position. If I disable it by using ScrollViewer.CanContentScroll="False" then it works fine.

<ListBox Name="Tree" DockPanel.Dock="Top" 
    ItemsSource="{Binding DataSource.OrderedLibraryItems}" 
    Background="{StaticResource LibraryBackground}"
    Width="220" HorizontalAlignment="Left"
    BorderThickness="0"
    VirtualizingStackPanel.IsVirtualizing="True"
    VirtualizingStackPanel.VirtualizationMode="Standard"
    ScrollViewer.IsDeferredScrollingEnabled="True"
    ScrollViewer.CanContentScroll="False"
    ItemTemplate="{StaticResource ListLibraryItemTemplate}"
    SelectionMode="Single"
    MouseDoubleClick="HandleMouseDoubleClick"
/>

But setting ScrollViewer.CanContentScroll="False" disables virtualization and I want to use virtualization to my ListBox so I set fixed Height and Width to the TextBlock. So, the DockPanel does not re-arrange it's children if I change the status message.

May be it's a bug at ScrollViewer. It should not change the scroll position if the size has not changed.

like image 83
user904627 Avatar answered Nov 14 '22 21:11

user904627