Damian
Damian

Reputation: 4763

WP7: Get current PivotItem for data-bound Pivot

I have a Pivot, whose ItemsSource is set to a collection of data objects, and I use an ItemTemplate to transform the items into UI content (I also use a HeaderTemplate).

When tombstoning, I normally get the ScrollViewer from the current PivotItem and save the current position away, so that I can scroll back to the right position if the user navigates back to my app. This works fine if I hard-code the PivotItems in my XAML.

My issue is that the when the Pivot is bound to my data object collection using ItemsSource, SelectedItem returns one of my data objects - not the PivotItem. I can't see how to get to the current PivotItem (or the UI elements generated from my ItemTemplate). I've noticed protected members to go from a ItemsSource item to its corresponding container - perhaps I need to derive from Pivot to make use of these?

Thanks!

Damian

Upvotes: 2

Views: 4058

Answers (4)

Ade A
Ade A

Reputation: 146

Another way to get the Pivot item is described here - http://bea.stollnitz.com/blog/?p=7

Get a referenec to the Pivot control and you can then use Pivot.ItemContainerGenerator.ContainerFromIndex(index) tp get the PivotItem or you can use Pivot.ItemContainerGenerator.ContainerFromItem(dataobject)

Upvotes: 4

Damian
Damian

Reputation: 4763

I've upvoted Derek's answer since it sent me in the right direction. The extension method he suggested only went one level deep though, so I've come up with the following recursive extension method which works for me:

internal static T FindVisualChild<T>(this DependencyObject parent,
                                    Func<T, bool> filter)
                                    where T : DependencyObject
{
    var childCount = VisualTreeHelper.GetChildrenCount(parent);
    for (var i = 0; i < childCount; i++)
    {
        var elt = VisualTreeHelper.GetChild(parent, i);
        if (elt is T && filter((T)elt)) return (T)elt;
        var result = FindVisualChild(elt, filter);
        if (result != null) return result;
    }
    return null;
}

And then I use it as follows:

var item = pivot.FindVisualChild<PivotItem>(
                          elt => elt.DataContext == pivot.SelectedItem);

This approach is just a refinement of Derek's -- all kudos to him.

Upvotes: 3

Derek Lakin
Derek Lakin

Reputation: 16319

If, for some reason, you need the actual current PivotItem and not the data that is associated with it, then I think you'll need to traverse the visual tree to find it. I use the following methods to help in this:

        /// <summary>
        /// Gets the visual children of type T.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="target"></param>
        /// <returns></returns>
        public static IEnumerable<T> GetVisualChildren<T>(this DependencyObject target)
            where T : DependencyObject
        {
            return GetVisualChildren(target).Where(child => child is T).Cast<T>();
        }


        /// <summary>
        /// Get the visual tree children of an element.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns>The visual tree children of an element.</returns>
        /// <exception cref="T:System.ArgumentNullException">
        /// <paramref name="element"/> is null.
        /// </exception>
        public static IEnumerable<DependencyObject> GetVisualChildren(this DependencyObject element)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }

            return GetVisualChildrenAndSelfIterator(element).Skip(1);
        }

        /// <summary>
        /// Get the visual tree children of an element and the element itself.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns>
        /// The visual tree children of an element and the element itself.
        /// </returns>
        private static IEnumerable<DependencyObject> GetVisualChildrenAndSelfIterator(this DependencyObject element)
        {
            Debug.Assert(element != null, "element should not be null!");

            yield return element;

            int count = VisualTreeHelper.GetChildrenCount(element);
            for (int i = 0; i < count; i++)
            {
                yield return VisualTreeHelper.GetChild(element, i);
            }
        }

So you would use this as follows:

var selectedPivotItem = this._pivot
    .GetVisualChildren()
    .Select(p => p.DataContext == this._pivot.SelectedItem)
    .FirstOrDefault();

Upvotes: 2

Jeff Wilcox
Jeff Wilcox

Reputation: 6385

Why not use the SelectedIndex property?

Upvotes: 1

Related Questions