ListView : how to always scroll to the bottom - c#

I have a list view that I want to scroll to the bottom as I add items into the "Items" list.
As I add items they appear in the ListView, but when I reach the limit of the screen, the list remains showing the top section and new items are added to the bottom. If I scroll down I can see the new items. I'd like it to auto scroll to the bottom so that I can always see the latest items in the list.
<ListView
x:Name="lvBasketContent"
Grid.Row="1"
ItemsSource="{Binding Items}"
ItemContainerStyle="{StaticResource ListViewItemStyle1}"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Bottom"
SelectionMode="None"
IsSwipeEnabled="False"
VerticalAlignment="Top"
>
Can anyone help me out please?

You need to create a custom behavior or derived implementation of ListView.
This class should monitor the ItemsSource collection for changes and call ListViewBase.ScrollIntoView(Object), passing in the item that you want to show. In your case, this may be the last one added.
I recommended the behavior as it keeps your code modular as you can use it on any listview in your solution by changing the xaml only.
I'm not going to write the code for you as behaviors are a very useful technique to learn first hand. The first link should give you all you need to get cracking.

Do you can try put this in your code ? Each time you add an item to your listbox , try call it
//Add an item in the listbox
lvBasketContent.Items.Add(...);
//...
//Scroll to bottom
lvBasketContent.SelectedIndex = lvBasketContent.Items.Count -1
lvBasketContent.ScrollIntoView(lvBasketContent.SelectedItem)

Related

Is there a feature to shift item on top in a listview

I have a ListView which ItemSource is bind to an ObservableCollection. This collection stores a list of some user's chat messages. Now I want to shift that item on top whenever that user receives a new chat message. Likewise in WhatsApp and slack app. So I want to know what is the correct way of doing this. Right now I am removing an item from the list and then adding it to the 0th index but this way sometimes I am getting parameter incorrect issues. So is there any way so that I can directly shift any chat to the top without removing it.
Xaml code for listview is below:
<ListView MaxHeight="{x:Bind ViewModel.OpenedChatMaxHeight, Mode=OneWay}"
Margin="0,10,0,0"
CanDragItems="True"
Loaded="{x:Bind ViewModel.OpenedChatDataLoaded}"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
SelectedIndex="{x:Bind ViewModel.OpenChatListSeletedItem,Mode=TwoWay}"
ItemsSource="{x:Bind ViewModel.OpenChatList,Mode=TwoWay}"
SelectionChanged="{x:Bind ViewModel.ChatSelected}"
IsItemClickEnabled="True"
ItemClick="{x:Bind ViewModel.OpenPinnedChatListItemClick}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsStackPanel ItemsUpdatingScrollMode="KeepItemsInView" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
The ObservableCollection<T> class has a Move method that you can use to move an item from one index to another:
OpenedChatMaxHeight.Move(oldIndex, 0);
This is more convenient than manually removing and adding the item back at index 0.
I have tried the Move method but in that case, I always get index out of range error my view just gets out of focus.
Move method will moves the item at the specified index to a new location in the collection. Please add debug point to check if the oldIndex is correct. Above problem looks you have not get correct oldindex.
Is there a feature to shift item on top in a listview
For fixing the chart item in the top, we often make a separate top list. When you want to fix the chart item, you could remove it from the previous chart list, and add it into top list.
For this way, it is easy to make a istop style, but not make datatemplete selector for previous list. And you could also store the istop chart items in local storage to improve rendering performance.

uwp - scrollviewer doesn't keep scroll position when content is updated

I have this following XAML for my ScrollViewer
<!-- Scroller -->
<ScrollViewer x:Name="Scroller"
Margin="0 75 0 0"
Width="1080"
Height="560"
HorizontalScrollMode="Enabled"
HorizontalScrollBarVisibility="Auto"
HorizontalSnapPointsType="MandatorySingle"
HorizontalSnapPointsAlignment="Center">
<StackPanel x:Name="StackItems"
Orientation="Horizontal"
Background="Transparent"
HorizontalAlignment="Center"
Width="Auto"
Padding="920 0 0 0">
</StackPanel>
</ScrollViewer>
The problem is when I use method Insert of StackPanel to add a new item, the new item push the current view to either left or right according to the index I add.
For example:
There are 5 items in my StackPanel now, and I scrolled to the last index (4th), then while I am viewing index 4th and I added new Item to the first as shown below, my current view will be pushed to item 3rd and I need to scroll right once to get the 4th Item again.
this.StackItems.Children.Insert(0, new Item());
For this following matter, Could anyone tell me how to keep the current viewport active even if there is new item is added to the StackPanel ?
Appreciate that. Thank you!
There are two ways I can think of right away that use the ScrollViewer.
All methods below assume you know the index of the item you want to bring into view. If you don't know this you can use the current scrolllocation or selected item (in case of a ListView) to obtain this index.
The first method is by using ScrollViewer.ChangeView():
After you have added a new item to StackItems you can add this line of code:
Scroller.ChangeView(
StackItems.Padding.Left +
StackItems.Children
.Take(indexToBringIntoView)
.Sum(u => u.ActualSize.X),
null,
null
);
If the width of all items are equal you can instead just write of course:
Scroller.ChangeView(StackItems.Padding.Left + itemWidth * indexToBringIntoView, null, null);
The second method is by using UIElement.StartBringIntoView():
This method is easier than the first method, however I have noticed some strange behaviour of the ScrollViewer when using this.
After adding your new item to the StackItems you can use the following the bring you previous item into view:
StackItems.Children[indexToBringIntoView].StartBringIntoView();
Another way of achieving your goal is to use a horizontal ListView
You can set this up following the accepted answer from this SO thread.
Then if you have the index of the item you want to bring into view you can use ListView.ScrollIntoView(object item) like so:
listView.ScrollIntoView(Lister.Items[indexToBringIntoView]);
I have included this method as well since this is a very solid working method and I never had a problem with it.
If this is not what you are looking for, let me know and I'll adjust my answer.

UWP - FlipView - Need FlipView to only load a single item content

I have been struggling for the last week trying to implement a FlipView in the like of the Microsoft News UWP app.
I tried the following: a FlipView With an ItemTemplate and an ObservableCollection with my items.
However this caused the whole lot of items within my ObservableCollection to be pre-loaded, which is not what I want.
Has anyone got any tip allowing me to change this behaviour of the FlipView to be as follows: Only the first item is loaded, then when I click the arrow, the next item gets loaded.
Thanks in advance :)
UPDATE:
I can confirm that the behaviour is as #Sunteen Wu - MSFT said.
I also tried using a similar logic to the one on fund the demo by #Martin Zikmund, however, it was not clearing the previous item
My goal is to load 1 single item at a time. The behaviour like so:
1) I see 1 item
2) If I click the > (next) arrow:
* this item is unloaded from the flipview
* the next item is loaded
3) if I click the < (previous) arrow:
* this item is unloaded from the flipview
* the previous item is re-loaded
Hope someone can help, I really want to give that feature to my users ^^.
However this caused the whole lot of items within my ObservableCollection to be pre-loaded
FlipView control's ItemsPanelTemplate contains VirtualizingStackPanel. So the FlipView control supports virtualization at default. You can check the visual tree when you debugging the app, you may find no matter how many items you bind to the FlipView, it only load three FlipViewItem at default.
So in my opinion, the FlipView will not pre-loaded the whole items of your ObservableCollection , by default it may load the previous one, current one and the next one, unless you change the ItemPanel to StackPanel which doesn't support virtualization.
<FlipView x:Name="flipView1" Width="480" Height="270"
BorderBrush="Black" BorderThickness="1">
<FlipView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</FlipView.ItemsPanel>
<FlipView.ItemTemplate>
...
</FlipView.ItemTemplate>
</FlipView>
Only the first item is loaded, then when I click the arrow, the next item gets loaded.
As FlipView using virtualization so that I guess you don't still need this feature. If you still want it, you can try to bind source to the FlipView with instance data is empty and every time the selection changed, force load the content manually. For this you may reference this similar thread that #Martin Zikmund provides a demo for single loading.
Additionally, according to Do's and don'ts remarks of FlipView:
Avoid using a flip view control for larger collections, as the repetitive motion of flipping through each item can be tedious.
If you do have a larger collection for binding, avoid using a flip view but consider a List view or grid view.

Dropping item between listviews animation

I have 2 ListView controls bound to 2 different ObservableCollection<string> like this:
<ListView x:Name="List1"
Grid.Column="0"
CanDragItems="True"
CanReorderItems="True"
AllowDrop="True"/>
<ListView x:Name="List2"
Grid.Column="1"
CanDragItems="True"
CanReorderItems="True"
AllowDrop="True"/>
When dragging and dropping items in their own respective lists I get the default animation like this:
But I cannot get the same animation when I hover over the second ListView. Why is that and how can I invoke the same animation in this case? I can handle what happens on drop but first I need to be able to invoke the same animation.
All current solution I have gone through does not have the animation or uses some other library/control to substitute for this. Any help or suggestion regarding this is appreciated.
There is no default drop animation for a ListView. You'll need to create something yourself - or use a third party solution such as you report to have already found.

Overwrite ListBoxitem?

I'm new to WPF and I have this ListBox which I want to instantiate with a specific ListBoxItem, so the user knows what to do with the ListBox.
<ListBox Name="DbListBox"
Grid.Column="3"
HorizontalAlignment="Left"
Height="246"
Margin="0,99,0,0"
Grid.Row="1"
VerticalAlignment="Top"
Width="211"
SelectionMode="Single"
SelectedItem="{Binding Path=selectedDB,Mode=TwoWay}"
AllowDrop="True"
Drop="DbListBox_Drop">
<ListBoxItem Name="ListBoxItem" FontStyle="Italic">Drag .db file here or add below</ListBoxItem>
</ListBox>
Then I have some code which adds a collection of items to the ItemsSource of this ListBox, but I can't do that since the ItemsSource is not empty
DbListBox.ItemsSource = DbCollection;
My question is, how can I start up the ListBox with the item inserted first, and then when DbCollection is added to it, it simply overwrites the first ListBoxItem?
When using WPF properly, we'd normally have something like this, where a collection property would be data bound to the ListBox.ItemsSource property:
<ListBox ItemsSource="{Binding SomeCollectionProperty}" />
Once we have this XAML, we don't need to touch the ListBox again, as we can add or remove items from the data bound collection and they will magically appear (or disappear) from the ListBox:
SomeCollectionProperty.Add(new SomeDataType());
SomeCollectionProperty.Remove(someItemFromCollection);
The SomeDataType used here is up to you... it depends on what you want to display in your items. If it was just a plain string for example, then you could simply do this to add your initial item into the collection:
SomeCollectionProperty.Add("Drag .db file here or add below");
If you wanted to make that item look different to the others then you'd need to data bind a custom class that has a Text property and FontStyle property for example. You could data bind these properties in a DataTemplate to design each item to be exactly as you want it. However, that's a completely different question.
To find out more about these things, you can read the Data Binding Overview and Data Templating Overview page on MSDN.

Categories

Resources