Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Simple WP7 JumpList in WPF

0.00/5 (No votes)
22 May 2011 1  
Recreating the Windows Phone 7 JumpList in WPF

Introduction

I am deeply impressed by Metro UI, the typography based design created by Microsoft. It is very clean and fast. In this article, I am demonstrating a simple example of how a WP7 JumpList can be created in WPF. The WP7 JumpList was demonstrated in the MIX '11 event.

WP7 JumpList Image

Using the Code

The WPF JumpList control is composed of two controls:

  • IndexControl - used to display the indices.
  • JumpListControl - encapsulates the contents of the JumpList.

IndexControl

The IndexControl is used to display the index in the ValuesPanel as well as the JumpListPanel. It has a dependency property IndexValue which is used to display the index value in the IndexControl.

public static readonly DependencyProperty IndexValueProperty =
    DependencyProperty.Register("IndexValue", typeof(string), typeof(IndexControl),
        new FrameworkPropertyMetadata
        ((new PropertyChangedCallback(OnIndexValueChanged))));

The IndexControl also has a dependency property IndexState to define its state.

public static readonly DependencyProperty IndexStateProperty =
    DependencyProperty.Register("IndexState", 
    typeof(IndexStateType), typeof(IndexControl),
    new FrameworkPropertyMetadata(IndexStateType.ListDisplay, 
    (new PropertyChangedCallback(OnIndexStateChanged))));

There are three states, defined by the enum IndexStateType.

public enum IndexStateType
{
    // The state when the IndexControl is displayed in the long list.
    ListDisplay,
    // The state when the IndexControl is displayed in the JumpList 
    // and this index has NO values
    IndexNotFound,
    // The state when the IndexControl is displayed in the JumpList 
    // and this index has values
    IndexFound
}

Based on its state, the look and feel of the IndexControl changes.

IndexState Types

JumpListControl

The WPF JumpList control has two panels:

  • ValuesPanel - used to display the values (names) in a long list format.
  • JumpListPanel - used to display the indices.

At any given instance, only one of the above panels is visible in the JumpListControl, while the other panel remains hidden.

ValuesPanel

WPF JumpList Image

The ValuesPanel displays the values (or names) in a long list format. For each index, the IndexControl and the set of Names are encapsulated in a StackPanel and added to the parent StackPanel.

Values Panel Image

JumpListPanel

WPF JumpList Image

The JumpListPanel consists of a WrapPanel in which the IndexControls are added.

JumpList Panel Image

The JumpListPanel defines two dependency properties:

  • Values - ObservableCollection<string> - serves as an input for the control.
    public static readonly DependencyProperty ValuesProperty =
        DependencyProperty.Register("Values", 
        typeof(ObservableCollection<string>), typeof(JumpListControl),
        new FrameworkPropertyMetadata
        ((new PropertyChangedCallback(OnValuesChanged))));
  • SelectedValue - indicates the value (or Name) selected by the user.
    public static readonly DependencyProperty SelectedValueProperty =
        DependencyProperty.Register("SelectedValue", 
        typeof(string), typeof(JumpListControl),
        new FrameworkPropertyMetadata
        ((new PropertyChangedCallback(OnSelectedValueChanged))));

When the JumpListControl is initialized, it adds IndexControls, to the JumpListPanel, for the indices a-z. The state of each of the IndexControls is set to IndexNotFound.

public JumpListControl()
{
    InitializeComponent();

    JumpListScrollView.Visibility = System.Windows.Visibility.Hidden;

    foreach (char idx in indexes)
    {
        IndexControl idxCtrl = new IndexControl
        {
            Width = 50,
            Height = 50,
            IndexValue = idx.ToString(),
            IndexState = IndexStateType.IndexNotFound,
            Margin = new Thickness(4, 4, 0, 0)
        };

        idxCtrl.MouseLeftButtonDown += 
            new MouseButtonEventHandler(OnIndexClickedInJumpList);

        JumpListPanel.Children.Add(idxCtrl);
    }
}

When the Values dependency property is set by the user, the JumpListControl parses the list and creates the indexed long list in the ValuesPanel and changes the state of the IndexControls, in the JumpListPanel, from IndexNotFound to IndexFound.

private void Parse(ObservableCollection<string> values)
{
    Dictionary<string, List<string>> valueDict = new Dictionary<string, List<string>>();

    List<string> valueList = values.ToList();

    // Sort the values
    valueList.Sort();

    // Get the distinct indexes
    foreach (string str in valueList)
    {
        string key = Char.ToLower(str[0]).ToString();
        if (!valueDict.ContainsKey(key))
        {
            valueDict[key] = new List<string>();
        }
        valueDict[key].Add(str);
    }

    // Set the IndexState of all the IndexControls 
    // whose index has been found as IndexFound
    JumpListPanel.Children.OfType<IndexControl>()
                          .Where(i => valueDict.Keys.Contains(i.IndexValue))
                          .All(i =>
                          {
                              i.IndexState = IndexStateType.IndexFound;
                              return true;
                          });


    // Add the index and the related names to the Values Panel
    foreach (string key in valueDict.Keys)
    {
        StackPanel stkPanel = new StackPanel 
	{ HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch };

        IndexControl idxCtrl = new IndexControl
        {
            Width = 50,
            Height = 50,
            IndexValue = key,
            IndexState = IndexStateType.ListDisplay,
            Margin = new Thickness(4),
            HorizontalAlignment = System.Windows.HorizontalAlignment.Left,
            VerticalAlignment = System.Windows.VerticalAlignment.Center
        };

        idxCtrl.MouseLeftButtonDown += 
		new MouseButtonEventHandler(OnIndexClickedInValuesPanel);

        stkPanel.Children.Add(idxCtrl);

        foreach (string str in valueDict[key])
        {
            TextBlock tb = new TextBlock
            {
                FontFamily = font,
                FontWeight = FontWeights.Light,
                FontSize = 22,
                Foreground = Brushes.White,
                TextAlignment = TextAlignment.Left,
                Margin = new Thickness(4, 4, 0, 0),
                Text = str,
                HorizontalAlignment = System.Windows.HorizontalAlignment.Left,
                VerticalAlignment = System.Windows.VerticalAlignment.Center
            };

            tb.MouseLeftButtonDown += new MouseButtonEventHandler(OnValueSelected);

            stkPanel.Children.Add(tb);
        }

        ValuesPanel.Children.Add(stkPanel);
    }
}

When the ValuesPanel is being displayed and the user clicks on any of the indices, then the ValuesPanel is hidden and the JumpListPanel is displayed. When the user clicks on any of the indices in the JumpListPanel, the JumpListPanel is hidden, the ValuesPanel is displayed and the ValuePanel scrolls to the index selected by the user.

Clicking on any of the Names will set the SelectedValue property of the JumpListControl.

EndPoint

What I have attempted here is a basic implementation of the JumpList control which accepts a list of strings as input. It can be further modified to accept a collection of objects (say a person's record) and an image can be displayed alongside each name in the ValuesPanel.

Points of Interest

An important lesson I learnt during the development of this control is that when you are adding items to a WrapPanel (say with Orientation=Horizontal) and the items extend beyond the height of the WrapPanel, then the vertical scrollbar will not appear automatically (even though you set ScrollViewer.VerticalScrollBarVisibility="Auto").

To overcome this problem, you need to wrap your WrapPanel with a ScrollViewer.

<ScrollViewer Name="JumpListScrollView"
              HorizontalScrollBarVisibility="Disabled"
              VerticalScrollBarVisibility="Auto">
    <WrapPanel Name="JumpListPanel"
               Orientation="Horizontal">
    </WrapPanel>
</ScrollViewer>

History

  • 22nd May, 2010 - Version 1.0 released

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here