Thursday, December 29, 2011

Add Scrolling Event in a List - WP7

Many of you might have been in  a situation when you desperately wanted to know if a scroll bar is scrolling or not.

Currently there is no direct provision to attain this in WP7. I'll walk through the code which will help you to identify if a list is scrolling or not. Later at the end there ia a full working sample attached.

My sample is straight forward. I'll be changing the page title to "Scrolling" when we scroll the list and "NotScrolling" while it is stationary.

We have a list called theList.

1. Now attach a Loaded event to the page constructor:

public MainPage()
{
    InitializeComponent();
    Loaded += new RoutedEventHandler(MainPage_Loaded);
    theList.ItemsSource = GetListData(60);
}

2. Define a variable to identify if ScrollEvent has been hooked already:

bool alreadyHookedScrollEvents = false;

3. Define MainPage_Loaded handler. All major work will be done here:

void MainPage_Loaded(object sender, RoutedEventArgs e)
{
    if (alreadyHookedScrollEvents)
        return;

    alreadyHookedScrollEvents = true;

    //This is the key player which holds the magic for this trick
    //This ScrollViewer is the first templated child of your List
    ScrollViewer viewer = FindSimpleVisualChild<ScrollViewer>(theList);

    if (viewer != null)
    {
        // Visual States are always on the first child of the control template 
        FrameworkElement element = VisualTreeHelper.GetChild(viewer, 0) as FrameworkElement;
        if (element != null)
        {
            VisualStateGroup group = FindVisualState(element, "ScrollStates");
            if (group != null)
            {
                group.CurrentStateChanging += group_CurrentStateChanging;
            }
        }
    }
}

4. Use this helper function to identify the first visual child (ScrollViewer):

T FindSimpleVisualChild<T>(DependencyObject element) where T : class
{
    while (element != null)
    {
        if (element is T)
            return element as T;
        element = VisualTreeHelper.GetChild(element, 0);
    }
    return null;
}

5. Actual even handler which identify a changed state for scrollviewer:

void group_CurrentStateChanging(object sender, VisualStateChangedEventArgs e)
{
    //for demonstration change page's title
    PageTitle.Text = e.NewState.Name;
}

6. Helper function to filter out the required VisualState:


VisualStateGroup FindVisualState(FrameworkElement element, string name)
{
    if (element == null)
        return null;

    IList<VisualStateGroup> groups = (IList<VisualStateGroup>)VisualStateManager.GetVisualStateGroups(element);
    foreach (VisualStateGroup group in groups)
        if (group.Name == name)
            return group;

    return null;
}

     
7. Another helper function to fill the data in list to demonstrate implementation:


ObservableCollection<int> GetListData(int count)
{
    sourceList = new ObservableCollection<int>();
    for (int i = 1; i <= count; i++)
    {
        sourceList.Add(i);
    }
    return sourceList;
}

     
Source Code