WP8: ListBox last row won't remain scrolled into view - c#

When vertically scrolling into view, I can pull the last row into view, but on releasing the drag, the last row springs back (partially) out of view. I think inaccuracy of measure can be attributed to a grid that I'm using as the listbox's header but I'm currently unable to fix this to that they work together correctly.
<Border>
<StackPanel>
<ScrollViewer ScrollViewer.HorizontalScrollBarVisibility="Auto">
<StackPanel>
<Grid x:Name="_headers"/>
<ListBox x:Name="_dataGrid"/>
</StackPanel>
</ScrollViewer>
</StackPanel>
</Border>
**Update
This example removes the scroll and also suffers from the same truncated row problem as the example above. The header grid row also doesn't scroll horizontally with the listbox rows which is an even bigger problem for my solution.
<Border>
<StackPanel>
<Grid x:Name="_headers"/>
<ListBox x:Name="_dataGrid"/>
</StackPanel>
</Border>

It's because you put ScrollViewer inside StackPanel. StackPanel doesn't limit control's size so the ScrollViewer can grow forever and never scroll properly. Its size must be limited. Grid can do it perfectly (if only the height of the row is set to *, not Auto).
Also, in my opinion you shouldn't put ListBox inside ScrollViewer, because ListBox already has its own scroll feature.

Never ever use a ListBox inside a ScrollViewer, you will run into scrolling conflicts.
As far as I can see, you need to add a header to your list. LongListSeelctor might be the best option, since it has got a Header property (also Footer):
See: http://www.geekchamp.com/articles/the-new-longlistselector-control-in-windows-phone-8-sdk-in-depth

Related

UWP GridView - How to maintain visible items upon resizing (Column count changes)

I have a GridView that I use to display thousands of images/thumbnails (using data binding). I used ImplicitAnimations to add transitions, so that when the control is resized and the number of columns changes - every item smoothly goes into the new position after the resize.
Problem
This all works fine when the user is at the top of the GridView but becomes a problem the further the user scrolls. The further you scroll, the more items are moved around when the number of columns changes. More rows are added/removed, but the Scrollbar is kept on the same position/offset which causes previously visible items to go far away from the view - and the user gets lost.
What I tried so far...
I tried working around this issue by tracking the first visible item on every scroll change event and then scrolling to it on SizeChanged event. The problem of this solution, however, is that it's really rough. Animations are no longer noticable and the whole experience is laggy.
Is there any better solution to this problem?
Illustration of the problem
Video example
I have also made a video to better illustrate the issue.
(The images have been blurred because some were NSFW)
Video Link
What I am looking for is a way for the scrollbar to adjust it's position on resize and stay on the same items the User was looking at - without messing up the animations.
Edit
So apparently this can't be solved any other way but manually scrolling to the item I wish to have visible on resize, which I already tried doing and had problems with the animations being really rough again because the ScrollToItem was happening AFTER the animations were being triggered.
So my question now is - can I scroll to an item on reorder/resize - BEFORE the animations get triggered? That way I think I could keep the smoothness. Using the resize event, however, doesn't work for this.
Edit 2 - Code sample
<GridView x:Name="mylist" animations:ReorderGridAnimation.Duration="600" ItemsSource="{Binding Source={StaticResource viewSource}}">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid Orientation="Horizontal" HorizontalAlignment="Center" Loaded="ItemsWrapGrid_Loaded"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.ItemTemplate>
<DataTemplate>
<Grid Width="300" Height="300" Background="Gainsboro">
<Image Source="{Binding ThumbnailImage}" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
GridView ItemSource is binded to the following CollectionView
<UserControl.Resources>
<controls:AdvancedCollectionView x:Key="viewSource" Source="{x:Bind Collection}" />
</UserControl.Resources>
I switched to the Community Toolkit for the animations and the AdvancedCollectionView. The custom panel is being used for 2 reasons - to get the Panel and apply implicit animations to it - and to keep the scrollbar on the rightmost side when HorizontalAlignment is Center.
The CollectionView is binded to an ObservableCollection.
To reproduce the issue - just add a lot of items into the ItemSource and try resizing the GridView at different scroll offsets (check video sample)
.
For your this issue, it may be caused by the ListView and GridView UI virtualization, you can try to use VariableSizedWrapGrid as the GridView's ItemsPanel,
<GridView>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
But it will cost much device memory and performance without virtualization. So you should also take into consideration displaying many images in once.
As for displaying the Item that the User is looking at, since there are many items displayed in the screen, the GridView does not know to track witch one.So also as #Pratyay's suggestion, you need to keep track of the item then make the ScrollView witch is in the GridView to scroll to the item.

WPF DataGrid: header misaligned and unnecessary scrollbar

I'm using the WPF DataGrid to display some data. The definition is the following:
<Grid>
<DataGrid x:Name="dataGridArchivio"
Grid.Row="1" Margin="3"
CanUserAddRows="True"
CanUserDeleteRows="False"
IsReadOnly="False"
AutoGenerateColumns="False"
RowEditEnding="dataGridArchivio_RowEditEnding">
<!-- Column definitions, irrelevant to our problem -->
</DataGrid>
</Grid>
The result I get is the following:
The problems are highlighted in the screenshot. To reiterate:
When the control first appears, the column header is misaligned with the cells. As you can see, it is missing that little gray triangle that rows have, which causes the bad alignment
There is an unnecessary horizontal Scrollbar. The DataGrid is inside a Grid and thus it should automatically resize.
The funny thing is: as soon as I either resize the window or move the horizontal Scrollbar everything gets fixed: the header re-align correctly and the Scrollbar disappears!
So, how can I fix this so that it looks correctly right from the start, without having to manually move the Scrollbar or resize the window?
Ok, found a solution:
<DataGrid RowHeaderWidth="0" ... />
This removes those gray boxes on the left, fixes the alignment and makes the ScrollBar disappear.

WPF change ListView scroll speed

I have a ListView with custom-made cells (items).
This ListView represents a conversation between two persons exchanging messages with my application. Each time a message is added, the conversation auto-scrolls to the last item.
I am facing a few "strange" issues :
When a user writes a rather long message (say, 10 lines), it can then take up almost the whole screen (meaning the space allocated to the ListView) which is normal of course but then the scrolling is somewhat broken.
First, when the list auto-scrolls to this message, a big white space appears below the item all the way down to the bottom of my ListView. See picture :
And when messages are very short (single line) :
Second, and in all cases, the scroll speed is way to fast. A single mous-wheel "stroke" (the feeling in your finger as you scroll) will move the scroll bar too fast : up to 4 small messages are scrolled ! That's too much !
So question is : how to control the scroll speed ? How to slow it down ? Why is there this big white space ? Thanks for the help !
[UPDATE 1]
Requested by #CurtisHx my ListView XAML is as follow :
http://pastebin.com/FFZGhi6w
I hope it helps understanding my issue!
One way to be to set ScrollViewer.CanContentScroll="False" on the ListView. https://social.msdn.microsoft.com/Forums/vstudio/en-US/47bd6a75-7791-4c0f-93ae-931e9a6540e7/smooth-scrolling-on-listbox?forum=wpf
You will loose virtualization on the ListView, so keep the number of elements in the ListView to something reasonable. That should fix the fast scroll speed.
Text Alignment
The text is being aligned correctly. Currently, the parent container limits the width of the TextBlocks. TextBlocks will fill all of the horizontal space it can before wrapping the text. So for long messages, the TextBlock will expand horizontally until it hits the limits of the parent container.
In order to get the staggered text, the width of the message needs to be less than width of the ListView. If you widen the window, you'll see the text become staggered. Below is a snippit of code, pointing out the TextBlock that needs to be width limited.
<ListView x:Name="ConversationList" ScrollViewer.IsDeferredScrollingEnabled="False" ScrollViewer.CanContentScroll="False" ScrollViewer.VerticalScrollBarVisibility="Auto"
BorderBrush="Transparent" Grid.Row="0" ScrollViewer.HorizontalScrollBarVisibility="Disabled" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,10,10">
<!-- Big Snip /!-->
<ListView.ItemTemplate>
<DataTemplate>
<!-- Snip /!-->
<Border Padding="0, 15, 0, 15">
<Grid x:Name="ConversationBubble">
<Grid.RenderTransform>
<TranslateTransform />
</Grid.RenderTransform>
<Border Margin="70, 5, 70, 5" HorizontalAlignment="{Binding Alignment}" BorderBrush="#ECECEC" Visibility="Visible" Background="#F1F1F2" Padding="10">
<StackPanel>
I know this is too late, but:
VirtualizingPanel.ScrollUnit="Pixel"

WPF ListBox Auto Width Changes Incorrectly When DataTemplate Has Visibility Bindings

I have a ListBox docked to the left of a window whose width should size to it's contents. When I scroll the listbox, it's width wobbles and becomes wider than it should be. Essentially what I think is happening is that the ListBox calculates the size of all it's children to determine it's own size, but only seems to evaluate visibility bindings for controls that are actually on the screen (presumably for performance reasons). The result is that it calculates the size of it's off-screen children incorrectly, reserving space for hidden controls.
If there are fewer items in the list than the window height (and thus no scrollbar), the list is always the correct width, and it always snaps to the correct width when you scroll to the top or bottom. It's only whilst the scrollbar is positioned somewhere inbetween that the width is wrong.
I've been wrestling with this problem all evening, trying various refactorings like using a DataTemplateSelector to abstract away the need for visibility bindings but I've ended up with really dirty workarounds I'm not happy with. I'd like to solve the actual problem at hand rather than dodge it. Any pointers would be much appreciated.
In the following example, the list appears to size itself to the width of both Foo and Bar. Changing the StackPanel orientation causes it to size to the width of whichever is longer out of Foo and Bar. Hope that makes sense.
<ListBox ItemsSource="{Binding Widgets}" DockPanel.Dock="Left">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Visibility="{Binding ShowFoo, Converter={StaticResource BoolToVisConverter}}" Text="{Binding Foo}" />
<TextBlock Visibility="{Binding ShowBar, Converter={StaticResource InverseBoolToVisConverter}}" Text="{Binding Bar}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This effect what you're describing does not have to do with the visibility bindings.
Essentially what I think is happening is that the ListBox calculates
the size of all it's children to determine it's own size, but only
seems to evaluate visibility bindings for controls that are actually
on the screen (presumably for performance reasons). The result is that
it calculates the size of it's off-screen children incorrectly,
reserving space for hidden controls.
This sounds correct to me. It's done for performance reasons. Also known as virtualization of ListBox. The other controls inherit this too, such as DataGrid.
In order to get rid of it, you can switch out VirtualizingStackPanel with the usual stackpanel:
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
You might, or might not suffer the performance penalty, if you have massive amount of items, but that's the life. If you do not like this, I suggest you not to have this requirement in the first place.

WPF ScrollViewer for ListBox -> Performance issues

I'm trying to create grid with listbox with Scrollbar.
It's done somehow like that:
<Grid>
<ListBox Name="xxx" ItemsSource="{Binding}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Visible">
....
</ListBox>
</Grid>
The problem is that if I use scrollbar, then the size of bar-button jumps back and forward within scrolling. If I remove ScrollViewer from properties and instead put ListBox in ScrollViewer tag, then everything is working perfect, except of terrible performance of rerendering UI (resize, move window, resource consuming). According to google it does "disable virtualization". This sounds crazy that there's no simple solution to get properly working scrollbar and usable UI without issues.
Is there compromise for both of these things? Virtualization + properly working scrollviewer with fixed size of scrollbar button.

Categories