Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bind/tie scroll position of two LongListSelectors

In my Windows Phone app, I've got two LongListSelectors side-by-side on a page. I would like to make it so that when the user scrolls one of them, the other one scrolls the same amount.

The two LongListSelectors have ItemTemplates that will always be of identical heights. You can kind of think of this as mimicking frozen columns in Excel (the left LongListSelector only scrolls vertically, the right one scrolls horizontally and vertically.

Can anyone point me in the right direction on how to do this? I'm willing to do it in code-behind or whatever if it can't be done with binding.

like image 663
Tim Avatar asked Jan 08 '14 15:01

Tim


2 Answers

You can accomplish this by hooking into the ViewportControl of the LongListSelector. When the viewport of one LLS changes, change the Viewport of the other LLS. I'm guessing you only need two LLS, so a single DependencyProperty should do the trick. I wrote up a blog with all of the details on how to accomplish this.

The short of it is the need for a DependencyProperty

public double ScrollPosition
{
    get { return (double)GetValue(ViewPortProperty); }
    set { SetValue(ViewPortProperty, value); }
}

public static readonly DependencyProperty ViewPortProperty = DependencyProperty.Register(
    "ScrollPosition", 
    typeof(double), 
    typeof(MyLongListSelector), 
    new PropertyMetadata(0d, OnViewPortChanged));

And set the property when the Viewport changes.

private void OnViewportChanged(object sender, ViewportChangedEventArgs args)
{
    ScrollPosition = _viewport.Viewport.Top;
}

Then bind the property to each LLS in your xaml

<dataBoundApp1:MyLongListSelector x:Name="MainLongListSelector" ItemsSource="{Binding Items}"
                                    ScrollPosition="{Binding ScrollPosition, ElementName=MainLongListSelector2, Mode=TwoWay}"/>
<dataBoundApp1:MyLongListSelector x:Name="MainLongListSelector2" ItemsSource="{Binding Items}" Grid.Column="1" 
                                    ScrollPosition="{Binding ScrollPosition, ElementName=MainLongListSelector, Mode=TwoWay}"/>
like image 199
Shawn Kendrot Avatar answered Oct 17 '22 10:10

Shawn Kendrot


While I've never developed for Windows Phone I'm very familiar with XAML from WPF and have had similiar problems where I've needed to sync the width of bars across several bar charts. My proposed solution uses Dependency Properties to allow you to bind your ListSelectors in XAML like with the SharedSizeGroup in Grids. If you're not familiar with Dependency Properties start by looking here. Since I don't have acces to the requiered assemblies for Windows Phone this hasn't been tested but it does work in very similiar scenarios.

public class SyncedLongListSelector : LongListSelector
{
    private ScrollBar scrollBar;

    private static readonly Dictionary<string, List<SyncedLongListSelector>> Groupings = new Dictionary<string, List<SyncedLongListSelector>>();

    public static readonly DependencyProperty GroupNameProperty =
        DependencyProperty.Register("GroupName", typeof(string), typeof(SyncedLongListSelector), new PropertyMetadata(default(string)));

    public string GroupName
    {
        get
        {
            return (string)GetValue(GroupNameProperty);
        }
        set
        {
            SetValue(GroupNameProperty, value);
        }
    }

    public override void OnApplyTemplate()
    {
        scrollBar = GetTemplateChild("VerticalScrollBar") as ScrollBar; // See my comments

        if (scrollBar != null)
            scrollBar.Scroll += OnScroll;

        base.OnApplyTemplate();
    }

    private void UpdateScrolPosition(double scrollBarValue)
    {
        scrollBar.Value = scrollBarValue;
    }

    private void OnScroll(object sender, ScrollEventArgs args)
    {
        foreach (var otherList in Groupings[GroupName].Where(l => !Equals(l, this)))
            otherList.UpdateScrolPosition(scrollBar.Value);
    }
}

scrollBar = GetTemplateChild("VerticalScrollBar") as ScrollBar; I found the string to use in the link you provided.

You might need to add something if setting scrollBar.Value raises the OnScroll-event so you don't get a stack overflow :)

Also adding the controls to the Grouping-dictionary is left as an execise to the reader, it should be quite easy. If making your own controls is new to you try this resource for starters.

To use your ready control simply add it in XAML like so: <yourNamespace:SyncedLongListSelector GroupName="MySyncedGroup" />

like image 39
Zache Avatar answered Oct 17 '22 10:10

Zache