English 中文(简体)
Xamarin Forms: Scroll to is not working when reversing the collection data
原标题:

I have 3 tabs on the top of the page where I am listing some data using ListView. When I tap on a tab I need to scroll to the end of the listview, I mean I need to scroll to the last item of the ListView. I am reversing the collection before setting it to the ListView. I used below codes to scroll to last item:

settingslistview.ScrollTo(tab1settingList[tab1settingList.Count - 1], ScrollToPosition.End, false);

This is working fine if we not reverse the data. But when reversing the scrolling is not working.

I am adding the sample codes of my demo project below:

MainPage.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ScrollToDemo.MainPage">

    <StackLayout>
        <Grid
            Margin="10,0,10,0"
            VerticalOptions="StartAndExpand">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="33*" />
                <ColumnDefinition Width="34*" />
                <ColumnDefinition Width="33*" />
            </Grid.ColumnDefinitions>

            <StackLayout
                Grid.Column="0"
                HorizontalOptions="FillAndExpand"
                Margin="2,0"
                VerticalOptions="FillAndExpand"
                Orientation="Vertical">

                <Label 
                    x:Name="tab1_label"
                    FontAttributes="Bold"
                    Text="Tab1"
                    Style="{StaticResource style1}"/>

                <StackLayout.GestureRecognizers>
                    <TapGestureRecognizer
                        Tapped="Tab1Tapped"
                        NumberOfTapsRequired="1">
                    </TapGestureRecognizer>
                </StackLayout.GestureRecognizers>
            </StackLayout>

            <StackLayout
                Grid.Column="1"
                HorizontalOptions="FillAndExpand"
                Margin="2,0" 
                VerticalOptions="FillAndExpand"
                Orientation="Vertical">

                <Label 
                    x:Name="tab2_label"
                    IsEnabled="False"
                    Text="Tab2"
                    Style="{StaticResource style1}"/>

                <StackLayout.GestureRecognizers>
                    <TapGestureRecognizer
                        Tapped="Tab2Tapped"
                        NumberOfTapsRequired="1">
                    </TapGestureRecognizer>
                </StackLayout.GestureRecognizers>
            </StackLayout>

            <StackLayout
                Grid.Column="2"
                HorizontalOptions="FillAndExpand"
                    Margin="2,0"
                VerticalOptions="FillAndExpand"
                Orientation="Vertical">

                <Label 
                    x:Name="tab3_label"
                    IsEnabled="False"
                    Text="Tab3"
                    Style="{StaticResource style1}"/>

                <StackLayout.GestureRecognizers>
                    <TapGestureRecognizer
                        Tapped="Tab3Tapped"
                        NumberOfTapsRequired="1">
                    </TapGestureRecognizer>
                </StackLayout.GestureRecognizers>
            </StackLayout>
        </Grid>

        <ListView   
            x:Name="settingslistview"
            HasUnevenRows="True"
            SelectionMode="None"
            SeparatorColor="#cecece"
            SeparatorVisibility="None">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <ViewCell.View>
                            <Frame
                                HasShadow="False"
                                Padding="8"
                                CornerRadius="{OnIdiom Phone=20, Tablet=30}"
                                BorderColor="#bdbdbd"
                                Margin="5"
                                BackgroundColor="{Binding BGColor}">

                                <StackLayout 
                                    VerticalOptions="FillAndExpand"
                                    Margin="5,0,5,0"
                                    Orientation="Horizontal">

                                    <Label 
                                        Text="{Binding Title}"
                                        HorizontalOptions="StartAndExpand"
                                        VerticalOptions="CenterAndExpand"
                                        TextColor="{Binding TextColor}">
                                        <Label.FontSize>
                                            <OnIdiom x:TypeArguments="x:Double">
                                                <OnIdiom.Phone>18</OnIdiom.Phone>
                                                <OnIdiom.Tablet>27</OnIdiom.Tablet>
                                                <OnIdiom.Desktop>18</OnIdiom.Desktop>
                                            </OnIdiom>
                                        </Label.FontSize>
                                    </Label>
                                </StackLayout>
                                <Frame.HeightRequest>
                                    <OnIdiom x:TypeArguments="x:Double">
                                        <OnIdiom.Phone>30</OnIdiom.Phone>
                                        <OnIdiom.Tablet>45</OnIdiom.Tablet>
                                        <OnIdiom.Desktop>30</OnIdiom.Desktop>
                                    </OnIdiom>
                                </Frame.HeightRequest>
                            </Frame>
                        </ViewCell.View>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
            <ListView.Footer>
                <Label/>
            </ListView.Footer>
        </ListView>
    </StackLayout>
</ContentPage>

MainPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace ScrollToDemo
{
    public partial class MainPage : ContentPage
    {
        public ObservableCollection<SettingPageItems> tab1settingList;
        public ObservableCollection<SettingPageItems> tab2settingList;
        public ObservableCollection<SettingPageItems> tab3settingList;
        public MainPage()
        {
            InitializeComponent();
            tab1settingList = new ObservableCollection<SettingPageItems>();
            tab2settingList = new ObservableCollection<SettingPageItems>();
            tab3settingList = new ObservableCollection<SettingPageItems>();
            Tab1Items();
            Tab2Items();
            Tab3Items();
        }

        private void Tab1Tapped(object sender, EventArgs e)
        {
            tab1_label.FontAttributes = FontAttributes.Bold;
            tab2_label.FontAttributes = FontAttributes.None;
            tab3_label.FontAttributes = FontAttributes.None;
            settingslistview.ItemsSource = tab1settingList.Reverse();
            if (tab1settingList.Count != 0)
            {
                Device.BeginInvokeOnMainThread(() =>
                {
                    settingslistview.ScrollTo(tab1settingList[tab1settingList.Count - 1], ScrollToPosition.End, false);
                });
            }
        }

        private void Tab2Tapped(object sender, EventArgs e)
        {
            tab1_label.FontAttributes = FontAttributes.None;
            tab2_label.FontAttributes = FontAttributes.Bold;
            tab3_label.FontAttributes = FontAttributes.None;
            settingslistview.ItemsSource = tab2settingList.Reverse();
            if (tab2settingList.Count != 0)
            {
                Device.BeginInvokeOnMainThread(() =>
                {
                    settingslistview.ScrollTo(tab2settingList[tab2settingList.Count - 1], ScrollToPosition.End, false);
                });
            }
        }

        private void Tab3Tapped(object sender, EventArgs e)
        {
            tab1_label.FontAttributes = FontAttributes.None;
            tab2_label.FontAttributes = FontAttributes.None;
            tab3_label.FontAttributes = FontAttributes.Bold;
            settingslistview.ItemsSource = tab3settingList.Reverse();
            if (tab3settingList.Count != 0)
            {
                Device.BeginInvokeOnMainThread(() =>
                {
                    settingslistview.ScrollTo(tab3settingList[tab3settingList.Count - 1], ScrollToPosition.End, false);
                });
            }
        }

        public void Tab1Items()
        {
            for(int i =1; i<= 20; i++)
            {
                tab1settingList.Add(new SettingPageItems() { Title = "Option"+i, BGColor = Color.FromHex("#e4e4e4"), TextColor = Color.Black });
            }
            settingslistview.ItemsSource = tab1settingList.Reverse();
        }

        public void Tab2Items()
        {
            for (int i = 21; i <= 40; i++)
            {
                tab2settingList.Add(new SettingPageItems() { Title = "Option" + i, BGColor = Color.FromHex("#FFEBEE"), TextColor = Color.Black });
            }
        }

        public void Tab3Items()
        {
            for (int i = 41; i <= 60; i++)
            {
                tab3settingList.Add(new SettingPageItems() { Title = "Option" + i, BGColor = Color.FromHex("#E8EAF6"), TextColor = Color.Black });
            }
        }
    }
}


public class SettingPageItems : INotifyPropertyChanged
{
    public string Title { get; set; }

    private Color bgColor;
    public Color BGColor
    {
        set
        {
            if (value != null)
            {
                bgColor = value;
                NotifyPropertyChanged();
            }
        }
        get
        {
            return bgColor;
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private Color textColor;
    public Color TextColor
    {
        set
        {
            if (value != null)
            {
                textColor = value;
                NotifyPropertyChanged();
            }
        }
        get
        {
            return textColor;
        }
    }

    private string imageSource;
    public string ImageSource
    {
        set
        {
            if (value != null)
            {
                imageSource = value;
                NotifyPropertyChanged();
            }
        }
        get
        {
            return imageSource;
        }
    }
}

App.xaml

<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ScrollToDemo.App">
    <Application.Resources>
        <Style x:Key="style1" TargetType="Label">
            <Setter Property="HorizontalTextAlignment" Value="Center"/>
            <Setter Property="HorizontalOptions" Value="CenterAndExpand"/>
            <Setter Property="VerticalTextAlignment" Value="Center"/>
            <Setter Property="TextColor" Value="Black" />
            <Setter Property="FontSize">
                <OnIdiom
                    x:TypeArguments="x:Double"
                    Phone="18"
                    Tablet="27"
                    Desktop="18"/>
            </Setter>
        </Style>
    </Application.Resources>
</Application>

I have uploaded a sample demo here. I need to scroll to the last item of the listview when switching to other tabs. Currently it is on top of the page when switching.

问题回答

Look at the following code:

    private void Tab1Tapped(object sender, EventArgs e)
    {
        ...
        settingslistview.ItemsSource = tab1settingList.Reverse();
        if (tab1settingList.Count != 0)
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                settingslistview.ScrollTo(tab1settingList[tab1settingList.Count - 1], ScrollToPosition.End, false);
            });
        }
    }

You use tab1settingList.Reverse(); and set it to ItemsSource. The Reverse method returns a reversed IEnumerable but it doesn t modify the origin collection. That means tab1settingList s order is not changed. So when you use scrollto method, the last item in tab1settingList is still option20.

You may do something like this:

private void Tab1Tapped(object sender, EventArgs e)
{
    ...
    ObservableCollection<SettingPageItems> reversedtab1settingList = new ObservableCollection<SettingPageItems>(tab1settingList.Reverse());


    settingslistview.ItemsSource = reversedtab1settingList;
    if (tab1settingList.Count != 0)
    {
     
        Device.BeginInvokeOnMainThread(() =>
        {
            settingslistview.ScrollTo(reversedtab1settingList[reversedtab1settingList.Count - 1], ScrollToPosition.End, false);
        });
    }
}

For more info, you may refer to Enumerable.Reverse(IEnumerable) Method

Hope it helps!





相关问题
How to customize flyout page top bar in xamarin forms

I want to customize top bar of Xamarin forms like following i want to add some of menus search-bar and profile icon with drop down I am trying to achieve this with flyoutpage control. Please help me ...

热门标签