Forum Xamarin.Forms

Scrolling multiple lists at the same time.

RicardoSRicardoS ESMember ✭✭✭
edited June 2020 in Xamarin.Forms

That is roughly the problem I have.
Here is the code:

<CollectionView x:Name="colview" VerticalScrollBarVisibility="Never" HorizontalScrollBarVisibility="Never" RemainingItemsThreshold="5">
                <CollectionView.ItemsLayout>
                    <GridItemsLayout Orientation="Horizontal"/>
                </CollectionView.ItemsLayout>
                <CollectionView.ItemTemplate>
                    <DataTemplate>
                        <Grid >
                            <Grid.RowDefinitions>
                                <RowDefinition Height="160"/> <RowDefinition Height="Auto"/>
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="120"/>
                            </Grid.ColumnDefinitions>
                            <Label Text="{Binding name}" BackgroundColor="{Binding backcol}" FontSize="20" FontAttributes="Bold" WidthRequest="100" Margin="0,0,0,2"
                                   HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
                                   HorizontalTextAlignment="Center" VerticalTextAlignment="Center"
                                   Grid.Column="0" Grid.Row="0"/>
                            <ListView ItemsSource="{Binding listtimes}" HasUnevenRows="False" SelectionMode="None" SeparatorVisibility="None" 
                                      VerticalScrollBarVisibility="Never" HorizontalScrollBarVisibility="Never"
                                      CachingStrategy="RecycleElementAndDataTemplate" Scrolled="ListView_Scrolled"
                                      Grid.Column="0" Grid.Row="1" >
                                <ListView.ItemTemplate>
                                    <DataTemplate>
                                        <ViewCell>
                                            <Label Text="{Binding time, StringFormat='{}{0:H\\:mm}'}" BackgroundColor="{Binding backgr}" FontSize="15" WidthRequest="100"
                                                   HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
                                                   HorizontalTextAlignment="Center" VerticalTextAlignment="Center"/>
                                        </ViewCell>
                                    </DataTemplate>
                                </ListView.ItemTemplate>
                            </ListView>
                        </Grid>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>

Yep, t's a CollectionView loaded by bindings. To make it short, we give it a collection of objects (let's call them "points", if you will) with 3 properties: "name" (string) "listtimes" (list) and "backcol" (another string). We then bind the property "name" to a label and "listtimes" to a ListView (this is where things get confusing). "listtimes" is another list of objects (call 'em "times") with their own variables: "time" (DateTime) and "backgr" (string). Both "backcol" and "backgr" are Hex codes for the background color of each label.

In the CS part of the code we do this:

List<point> points = new List<point>([all data goes here]);
colview.ItemsSource = points;

and the rest is binding...

As you can see, the ListViews have a "Scrolled" property, but we are unable to access the other lists in order to, when one is scrolled, scroll the rest equally. I know this sound ridiculous but, hey, I can't contradict my higher-ups! That's what they want and that's what I'm asking.

Thank you very much and apologies for this mess.

Best regards.

P.S.: Some of the ListViews may not have the same amount of lines. In fact a handful of them might have so few items that cannot scroll. Sooo yeah...

Answers

  • LeonLuLeonLu Member, Xamarin Team Xamurai

    I cannot achieve it by your layout design. However, based on your layout design, I think Xamarin.Forms.DataGrid nuget package is suitable for your needs.

    https://github.com/akgulebubekir/Xamarin.Forms.DataGrid

    First of all, Here is a running GIF that used Xamarin.Forms.DataGrid.

    Here is layout code about use Xamarin.Forms.DataGrid nuget package.

     <dg:DataGrid ItemsSource="{Binding MyTimers}" SelectionEnabled="True" 
                   RowHeight="70" HeaderHeight="50" BorderColor="#CCCCCC" HeaderBackground="#E0E6F8"
                  >
                <dg:DataGrid.HeaderFontSize>
                    <OnIdiom  x:TypeArguments="x:Double">
                        <OnIdiom.Tablet>15</OnIdiom.Tablet>
                        <OnIdiom.Phone>13</OnIdiom.Phone>
                    </OnIdiom>
                </dg:DataGrid.HeaderFontSize>
                <dg:DataGrid.Columns>
                    <dg:DataGridColumn Title="Time1" PropertyName="Time1" >
                        <!--<dg:DataGridColumn.CellTemplate>
                            <DataTemplate>
                                <Image Source="{Binding Logo}" HorizontalOptions="Center" VerticalOptions="Center" Aspect="AspectFit" HeightRequest="60" />
                            </DataTemplate>
                        </dg:DataGridColumn.CellTemplate>-->
                    </dg:DataGridColumn>
                    <dg:DataGridColumn Title="Time2" PropertyName="Time2" />
                    <dg:DataGridColumn Title="Time3" PropertyName="Time3"  />
                    <dg:DataGridColumn Title="Time4" PropertyName="Time4"  />
                    <dg:DataGridColumn Title="Time5" PropertyName="Time5" />
                    <dg:DataGridColumn Title="Time6" PropertyName="Time6"   />
                    <dg:DataGridColumn Title="Time7" PropertyName="Time7"  >
                        <!--<dg:DataGridColumn.CellTemplate>
                            <DataTemplate>
                                <ContentView HorizontalOptions="Fill" VerticalOptions="Fill" 
                               BackgroundColor="{Binding Streak,Converter={StaticResource StreakToColorConverter}}">
                                    <Label Text="{Binding Streak}" HorizontalOptions="Center" VerticalOptions="Center" TextColor="Black"/>
                                </ContentView>
                            </DataTemplate>
                        </dg:DataGridColumn.CellTemplate>-->
                    </dg:DataGridColumn>
                </dg:DataGrid.Columns>
                <dg:DataGrid.RowsBackgroundColorPalette>
                    <dg:PaletteCollection>
                        <Color>#F2F2F2</Color>
                        <Color>#FFFFFF</Color>
                    </dg:PaletteCollection>
                </dg:DataGrid.RowsBackgroundColorPalette>
    
            </dg:DataGrid>
    

    Here is layout's background code.

      public partial class Page1 : ContentPage
        {
            public Page1()
            {
                InitializeComponent();
                this.BindingContext = new TimerViewModel();
            }
        }
    

    Here is Model.cs

       public class MyTimer
        {
            public string Time1 { get; set; }
            public string Time2 { get; set; }
            public string Time3 { get; set; }
            public string Time4 { get; set; }
            public string Time5 { get; set; }
            public string Time6 { get; set; }
            public string Time7 { get; set; }
        }
    

    Here is viewModel.cs

      public class TimerViewModel : INotifyPropertyChanged
        {
            private List<MyTimer> myTimers;
            public List<MyTimer> MyTimers
            {
                get { return myTimers; }
                set { myTimers = value; OnPropertyChanged(nameof(MyTimers)); }
            }
            public TimerViewModel()
            {
                MyTimers = new List<MyTimer>();
                myTimers.Add(new MyTimer()
                {
                    Time1 = DateTime.Now.ToString(),
                    Time2 = DateTime.Now.ToString(),
                    Time3 = DateTime.Now.ToString(),
                    Time4 = DateTime.Now.ToString(),
                    Time5 = DateTime.Now.ToString(),
                    Time6 = DateTime.Now.ToString(),
                    Time7 = DateTime.Now.ToString()
                });
                myTimers.Add(new MyTimer()
                {
                    Time1 = DateTime.Now.ToString(),
                    Time2 = DateTime.Now.ToString(),
                    Time3 = DateTime.Now.ToString(),
                    Time4 = DateTime.Now.ToString(),
                    Time5 = DateTime.Now.ToString(),
                    Time6 = DateTime.Now.ToString(),
                    Time7 = DateTime.Now.ToString()
                });
                myTimers.Add(new MyTimer()
                {
                    Time1 = DateTime.Now.ToString(),
                    Time2 = DateTime.Now.ToString(),
                    Time3 = DateTime.Now.ToString(),
                    Time4 = DateTime.Now.ToString(),
                    Time5 = DateTime.Now.ToString(),
                    Time6 = DateTime.Now.ToString(),
                    Time7 = DateTime.Now.ToString()
                });
                myTimers.Add(new MyTimer()
                {
                    Time1 = DateTime.Now.ToString(),
                    Time2 = DateTime.Now.ToString(),
                    Time3 = DateTime.Now.ToString(),
                    Time4 = DateTime.Now.ToString(),
                    Time5 = DateTime.Now.ToString(),
                    Time6 = DateTime.Now.ToString(),
                    Time7 = DateTime.Now.ToString()
                });
                myTimers.Add(new MyTimer()
                {
                    Time1 = DateTime.Now.ToString(),
                    Time2 = DateTime.Now.ToString(),
                    Time3 = DateTime.Now.ToString(),
                    Time4 = DateTime.Now.ToString(),
                    Time5 = DateTime.Now.ToString(),
                    Time6 = DateTime.Now.ToString(),
                    Time7 = DateTime.Now.ToString()
                });
                myTimers.Add(new MyTimer()
                {
                    Time1 = DateTime.Now.ToString(),
                    Time2 = DateTime.Now.ToString(),
                    Time3 = DateTime.Now.ToString(),
                    Time4 = DateTime.Now.ToString(),
                    Time5 = DateTime.Now.ToString(),
                    Time6 = DateTime.Now.ToString(),
                    Time7 = DateTime.Now.ToString()
                });
                myTimers.Add(new MyTimer()
                {
                    Time1 = DateTime.Now.ToString(),
                    Time2 = DateTime.Now.ToString(),
                    Time3 = DateTime.Now.ToString(),
                    Time4 = DateTime.Now.ToString(),
                    Time5 = DateTime.Now.ToString(),
                    Time6 = DateTime.Now.ToString(),
                    Time7 = DateTime.Now.ToString()
                });
                myTimers.Add(new MyTimer()
                {
                    Time1 = DateTime.Now.ToString(),
                    Time2 = DateTime.Now.ToString(),
                    Time3 = DateTime.Now.ToString(),
                    Time4 = DateTime.Now.ToString(),
                    Time5 = DateTime.Now.ToString(),
                    Time6 = DateTime.Now.ToString(),
                    Time7 = DateTime.Now.ToString()
                });
                myTimers.Add(new MyTimer()
                {
                    Time1 = DateTime.Now.ToString(),
                    Time2 = DateTime.Now.ToString(),
                    Time3 = DateTime.Now.ToString(),
                    Time4 = DateTime.Now.ToString(),
                    Time5 = DateTime.Now.ToString(),
                    Time6 = DateTime.Now.ToString(),
                    Time7 = DateTime.Now.ToString()
                });
                myTimers.Add(new MyTimer()
                {
                    Time1 = DateTime.Now.ToString(),
                    Time2 = DateTime.Now.ToString(),
                    Time3 = DateTime.Now.ToString(),
                    Time4 = DateTime.Now.ToString(),
                    Time5 = DateTime.Now.ToString(),
                    Time6 = DateTime.Now.ToString(),
                    Time7 = DateTime.Now.ToString()
                });
                myTimers.Add(new MyTimer()
                {
                    Time1 = DateTime.Now.ToString(),
                    Time2 = DateTime.Now.ToString(),
                    Time3 = DateTime.Now.ToString(),
                    Time4 = DateTime.Now.ToString(),
                    Time5 = DateTime.Now.ToString(),
                    Time6 = DateTime.Now.ToString(),
                    Time7 = DateTime.Now.ToString()
                });
                myTimers.Add(new MyTimer()
                {
                    Time1 = DateTime.Now.ToString(),
                    Time2 = DateTime.Now.ToString(),
                    Time3 = DateTime.Now.ToString(),
                    Time4 = DateTime.Now.ToString(),
                    Time5 = DateTime.Now.ToString(),
                    Time6 = DateTime.Now.ToString(),
                    Time7 = DateTime.Now.ToString()
                });
                myTimers.Add(new MyTimer()
                {
                    Time1 = DateTime.Now.ToString(),
                    Time2 = DateTime.Now.ToString(),
                    Time3 = DateTime.Now.ToString(),
                    Time4 = DateTime.Now.ToString(),
                    Time5 = DateTime.Now.ToString(),
                    Time6 = DateTime.Now.ToString(),
                    Time7 = DateTime.Now.ToString()
                });
                myTimers.Add(new MyTimer()
                {
                    Time1 = DateTime.Now.ToString(),
                    Time2 = DateTime.Now.ToString(),
                    Time3 = DateTime.Now.ToString(),
                    Time4 = DateTime.Now.ToString(),
                    Time5 = DateTime.Now.ToString(),
                    Time6 = DateTime.Now.ToString(),
                    Time7 = DateTime.Now.ToString()
                });
                myTimers.Add(new MyTimer()
                {
                    Time1 = DateTime.Now.ToString(),
                    Time2 = DateTime.Now.ToString(),
                    Time3 = DateTime.Now.ToString(),
                    Time4 = DateTime.Now.ToString(),
                    Time5 = DateTime.Now.ToString(),
                    Time6 = DateTime.Now.ToString(),
                    Time7 = DateTime.Now.ToString()
                });
    
            }
    
            #region INotifyPropertyChanged implementation
            public event PropertyChangedEventHandler PropertyChanged;
    
            private void OnPropertyChanged(string property)
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
    
            #endregion
        }
    }
    
    

    In the end, do not forget to add Xamarin.Forms.DataGrid.DataGridComponent.Init(); in your App.xaml.cs

  • LeonLuLeonLu Member, Xamarin Team Xamurai

    @RicardoS Are there any update for this issue? If this above answer is helpful, please accept it, it will help others who have similar issue.

  • RicardoSRicardoS ESMember ✭✭✭

    Thank you for your response, @LeonLu

    Unfortunately, this object was not what we were looking for on the principle that we obtain the data of our list from an API and have no idea how many columns it has beforehand.
    I think that I should have mention that.

    Regards

  • LeonLuLeonLu Member, Xamarin Team Xamurai

    If you use MVVM method, it cannot be achieved about scrolling multiple lists at the same time. Because all of models are independented, they are cannot be scrolled multiple lists at the same time.

Sign In or Register to comment.