0

I'm building a UWP app using C# and having trouble getting multiple listviews to scroll simultaneously.

I have 3 listviews: ListViewA, ListViewB and ListViewC.

If I scroll ListViewA, then both ListViewB and ListViewC should scroll. If I scroll ListView B, then ListViewA and ListViewC will scroll, and the same is true if I scroll ListViewC.

I've done the usual searching and trying examples here on Stackoverflow, along with following links provided by other members. Still not getting the solution to this problem. Hoping someone here might be able to shed some light, or offer some insight on where to look?

I'm using an MVVM approach to populate the listviews and that functions as expected.

It's now just getting all 3 listviews to scroll at once. Let me know if you need any additional info. Thanks.

public class TestModel
{
    int ID {get; set;}
    string ColumnA {get; set;}
    string ColumnB {get; set;}
    string ColumnC {get; set;}  
}

public class MainPage : Page
{
        public TestModelViewModel ViewModel { get; set; }
        public MainPage()
        {
            this.InitializeComponent();
            ViewModel = new TestModelViewModel("Filename=TestModelDB.db");
        }
}

<ListView x:Name="ListViewA" ItemsSource="{x:Bind ViewModel.CollectionOfTestModelData, Mode=OneWay}">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="viewModels:TestModelViewModel" >
            <StackPanel>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Column="0" Text="{x:Bind ColumnA, Mode=OneWay}"/>
                </Grid>
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

<ListView x:Name="ListViewB" ItemsSource="{x:Bind ViewModel.CollectionOfTestModelData, Mode=OneWay}">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="viewModels:TestModelViewModel" >
            <StackPanel>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Column="0" Text="{x:Bind ColumnB, Mode=OneWay}"/>
                </Grid>
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

<ListView x:Name="ListViewC" ItemsSource="{x:Bind ViewModel.CollectionOfTestModelData, Mode=OneWay}">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="viewModels:TestModelViewModel" >
            <StackPanel>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Column="0" Text="{x:Bind ColumnC, Mode=OneWay}"/>
                </Grid>
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>
MikeJP
  • 13
  • 3

1 Answers1

0

First,you can subscribe PointerEntered event to judge which listView is scrolled.Below I only use ListViewA and ListViewB as an example.

public bool ScrollViewerAScrolled = false;
public bool ScrollViewerBScrolled = false;

ListViewA.PointerEntered += ListViewA_PointerEntered;
ListViewB.PointerEntered += ListViewB_PointerEntered;

private void ListViewB_PointerEntered(object sender, PointerRoutedEventArgs e)
        {​
            ScrollViewerBScrolled = true;​
            ScrollViewerAScrolled = false;​
        }​


private void ListViewA_PointerEntered(object sender, PointerRoutedEventArgs e)​
        {​
            ScrollViewerAScrolled = true;​
            ScrollViewerBScrolled = false;​
        }

Then,you can get the ScrollViewer in the listView by VisualTreeHelper(Need to be called after the ListView is loaded). And subscribe the ViewChanged event.For example,When ListViewA scrolls,the event will be triggered,you can scoll ListViewB and ListViewC in this event.The same applies to ListViewB and ListViewC.

var scrollViewerA = FindVisualChild<ScrollViewer>(ListViewA, "ScrollViewer");
var scrollViewerB = FindVisualChild<ScrollViewer>(ListViewB, "ScrollViewer");
scrollViewerA.ViewChanged += (s, e) =>
            {​
                if (ScrollViewerAScrolled)​  
                {​
                    scrollViewerB.ChangeView(null, scrollViewerA.VerticalOffset, null, false);​
                }
             ​
                ​
           };​

scrollViewerB.ViewChanged += (s, e) =>​
            {​
    ​
                 if (ScrollViewerBScrolled)​
                 {​
                     scrollViewerA.ChangeView(null, scrollViewerB.VerticalOffset, null, false);​
                      ​
                 }​

             };

Here is how to get the ScrollViewr in ListView:

protected T FindVisualChild<T>(DependencyObject obj, string name) where T : DependencyObject
            {
                //get number
                int count = VisualTreeHelper.GetChildrenCount(obj);

                //Traversing each object based on the index
                for (int i = 0; i < count; i++)
                {
                    var child = VisualTreeHelper.GetChild(obj, i);
                    //According to the parameters to determine whether we are looking for the object
                    if (child is T && ((FrameworkElement)child).Name == name)
                    {
                        return (T)child;
                    }
                    else
                    {
                        var child1 = FindVisualChild<T>(child, name);

                        if (child1 != null)
                        {
                            return (T)child1;
                        }


                    }
                }

                return null;

            }
Faywang - MSFT
  • 5,798
  • 1
  • 5
  • 8
  • Thank you for the reply. I understand the first part, the second part I'm struggling with a bit. Are you creating a new instance of a ScrollViewer in the code-behind, or creating a new UI element in Xaml? Also, you mentioned VisualTreeHelper, not too familiar with it, but would a good source be here at this [link](https://stackoverflow.com/questions/32557216/windows-10-scrollintoview-is-not-scrolling-to-the-items-in-the-middle-of-a-lis)? – MikeJP Aug 02 '19 at 19:29
  • ListView template always includes a ScrollViewer,so what I did was to get his child object "ScrollViewer".The [VisualTreeHelper](https://learn.microsoft.com/en-us/uwp/api/windows.ui.xaml.media.visualtreehelper) is used to traverse object relationships (along child-object or parent-object axes).You can use it to get a specific child-object from parent-object.The link you showed is correct and I have edited my answer,you can try it. – Faywang - MSFT Aug 05 '19 at 01:25
  • After I replied, I did a little research and learned about how to access the ScrollViewer in the listview. I tried implementing what I learned from that link (btw thanks for confirming :) along with your solution and made some awesome progress, but still not all the way there yet. Your second reply makes sense, and reviewing your edits now so I understand the concept better. I'll let you know how it goes once I integrate the changes. – MikeJP Aug 07 '19 at 05:10