Search code examples
silverlightwindows-phone-7panorama-control

How can you synchronise the position of multiple PanoramaItems?


I have a standard Panorama-based application, but one key item of data is repeated in two adjacent PanoramaItems.

I would like those two PanoramaItems to have the same vertical scroll position (to save the user having to find the key item again).

Is there a way to get and set the scroll position of the PanoramaItem control and detect the scroll change?

Generic solution (thanks to Paul Diston for the clues):

    /// <summary>
    /// Scroll each new PanoramaItem to the same position as the previous one
    /// </summary>
    private void Panorama_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (e.RemovedItems.Count > 0 && e.AddedItems.Count > 0)
        {
            // Add logic here if only specific PanoramaItems are required to sync

            ScrollViewer firstChildAsScrollViewer =
                GetChildOfType(e.RemovedItems[0] as DependencyObject, typeof (ScrollViewer)) as ScrollViewer;
            ScrollViewer secondChildAsScrollViewer =
                GetChildOfType(e.AddedItems[0] as DependencyObject, typeof (ScrollViewer)) as ScrollViewer;
            if ((firstChildAsScrollViewer != null) && (secondChildAsScrollViewer != null))
            {
                secondChildAsScrollViewer.ScrollToVerticalOffset(firstChildAsScrollViewer.VerticalOffset);
            }
        }
    }

    /// <summary>
    /// Bredth-first recursive check for a child of the specified type
    /// </summary>
    private DependencyObject GetChildOfType(DependencyObject element, Type type)
    {
        int count = VisualTreeHelper.GetChildrenCount(element);
        for (int i = 0; i < count; i++)
        {
            var e = VisualTreeHelper.GetChild(element, i);
            if (e.GetType() == type)
            {
                return e;
            }
        }
        // Now try the grandchildren
        for (int i = 0; i < count; i++)
        {
            var e = VisualTreeHelper.GetChild(element, i);
            var ret = GetChildOfType(e, type);
            if (ret != null)
            {
                return ret;
            }
        }
        return null;
    }

Solution

  • You could use the VisualTreeHelper to access and set the VerticalOffset of the ScrollViewer of the ListBox controls :-

        private void Panorama_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            DependencyObject firstChild = VisualTreeHelper.GetChild(this.FirstListBox, 0);
    
            ScrollViewer firstChildAsScrollViewer = firstChild as ScrollViewer;
    
            DependencyObject secondChild = VisualTreeHelper.GetChild(this.SecondListBox, 0);
    
            ScrollViewer secondChildAsScrollViewer = secondChild as ScrollViewer;
    
            if ((firstChildAsScrollViewer != null) && (secondChildAsScrollViewer != null))
            {
                secondChildAsScrollViewer.ScrollToVerticalOffset(firstChildAsScrollViewer.VerticalOffset);
            }
        }
    

    Hope this helps.

    Paul Diston