Click here to Skip to main content
Click here to Skip to main content
Technical Blog

A Windows Phone 7 Slide View with Page Pips

, 8 Dec 2011 CPOL
Rate this:
Please Sign up or sign in to vote.
A slide view with page pips on Windows Phone 7.

A popular user-interface in the iOS world is the UIPageControl which renders a small set of dots to indicate the number of pages, with the current page highlighted in some way. This is often used in conjunction with a UIScrollView to navigate between pages in a multi-page layout.

Windows Phone 7 has a Pivot control which allows you to swipe in order to navigate content across multiple screens. However, the Pivot control is most often used when each ‘page’ has some logic header – in some ways it is analogous to a desktop tab control. I decided to use this control, without specifying headers for each PivotItem, then add my own control to render the ‘pips’.

The control that displays the location pips is defined in XAML, with the relationship between this control and the Pivot created via an ElementName binding:

<local:PivotLocationView Source="{Binding ElementName=pivot}"
                          HorizontalAlignment="Center"
                          VerticalAlignment="Bottom"
                          Margin="0,0,0,10"/>

<controls:Pivot Margin="0,-30,0,40" 
                x:Name="pivot">
  <controls:PivotItem>
    ...
  </controls:PivotItem>
  <controls:PivotItem>
    ...
  </controls:PivotItem>
  <controls:PivotItem>
    ...
  </controls:PivotItem>
</controls:Pivot>

Note the negative top margin for the Pivot, this control still allocates some header space, even when no headers are defined.

The PivotLocationView user control is backed by a simple view model, with model-items for each pip. When the view model is associated with a Pivot control, it creates a child view model for each Pivot Item, then handles the SelectionChanged event in order to keep the selection state synchronized:

public class PivotLocationViewModel
{
  private Pivot _pivot;

  public PivotLocationViewModel()
  {
  }

  public PivotLocationViewModel(Pivot pivot)
  {
    PivotItems = new PivotItemViewModelCollection();
    SetPivot(pivot);
  }

  /// <span class="code-SummaryComment"><summary>
</span>  /// Gets or sets the collection of child view-models
  /// <span class="code-SummaryComment"></summary>
</span>  public PivotItemViewModelCollection PivotItems { get; set; }

  private void SetPivot(Pivot pivot)
  {
    _pivot = pivot;

    // handle selection changed
    pivot.SelectionChanged += Pivot_SelectionChanged;

    // create a view model for each pivot item.
    for(int i=0;i<pivot.Items.Count;i++)
    {
      PivotItems.Add(new PivotItemViewModel());
    }

    // set the initial selection
    PivotItems[_pivot.SelectedIndex].IsSelected = true;
  }

  /// <span class="code-SummaryComment"><summary>
</span>  /// Handle selection changes to update the view model
  /// <span class="code-SummaryComment"></summary>
</span>  private void  Pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
  {
 	  var selectedModel = PivotItems.SingleOrDefault(p => p.IsSelected);
    if (selectedModel != null)
      selectedModel.IsSelected = false;

    PivotItems[_pivot.SelectedIndex].IsSelected = true;
  }
}

The view model for each pivot item is a simple model that implements INotifyPropertyChanged. It has an IsSelected property that reflects the selection state of the Pivot, it also exposes a Color property that indicates the color for each ‘pip’. This could have been implemented as a value converter, but there is little point as we already have a view model:

/// <span class="code-SummaryComment"><summary>
</span>/// A view model for each 'pip'
/// <span class="code-SummaryComment"></summary>
</span>public class PivotItemViewModel : INotifyPropertyChanged
{
  // ... INotifyPropertyChanged implementation

  private bool _isSelected;

  public bool IsSelected
  {
    get { return _isSelected; }
    set
    {
      if (_isSelected == value)
        return;

      _isSelected = value;
      OnPropertyChanged("IsSelected");
      Color = IsSelected ? Colors.Black : Colors.White;
    }
  }

  private Color _color;

  public Color Color
  {
    get { return _color; }
    set
    {
      _color = value;
      OnPropertyChanged("Color");
    }
  }
}

The XAML for this control is very simple, using an ItemsControl to render an ellipse for each ‘pip’:

<UserControl ...
    d:DataContext="{d:DesignData Source=PivotLocationViewModel.xml}">

  <Grid x:Name="LayoutRoot">
    <ItemsControl ItemsSource="{Binding PivotItems}">
      <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
          <StackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
      </ItemsControl.ItemsPanel>
      <ItemsControl.ItemTemplate>
        <DataTemplate>
          <Ellipse Width="12" Height="12" Margin="15,0,15,0"
                   Stroke="Black"
                   StrokeThickness="0.5">
            <Ellipse.Fill>
              <SolidColorBrush Color="{Binding Color}"/>
            </Ellipse.Fill>
          </Ellipse>
        </DataTemplate>
      </ItemsControl.ItemTemplate>
    </ItemsControl>
  </Grid>
</UserControl>

Note, the use of design-time data. The following file defines a view model instance:

<PivotLocationViewModel xmlns="clr-namespace:SlideView">
  <PivotLocationViewModel.PivotItems>
    <PivotItemViewModelCollection>
      <PivotItemViewModel IsSelected="False" Color="Red"/>
      <PivotItemViewModel IsSelected="True"  Color="Green"/>
      <PivotItemViewModel IsSelected="False"  Color="Red"/>
      <PivotItemViewModel IsSelected="False"  Color="Red"/>
    </PivotItemViewModelCollection>
  </PivotLocationViewModel.PivotItems>
</PivotLocationViewModel>

This makes creating the above user control much easier, because it can be visualised in the designer:

And there you have it, a simple user-control, which when used in conjunction with a Pivot, provides an interface where the user can swipe between pages.

You can download the full source code: SlideView.zip

Regards, Colin E.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Colin Eberhardt
Architect Scott Logic
United Kingdom United Kingdom
I am CTO at ShinobiControls, a team of iOS developers who are carefully crafting iOS charts, grids and controls for making your applications awesome.
 
I am a Technical Architect for Visiblox which have developed the world's fastest WPF / Silverlight and WP7 charts.
 
I am also a Technical Evangelist at Scott Logic, a provider of bespoke financial software and consultancy for the retail and investment banking, stockbroking, asset management and hedge fund communities.
 
Visit my blog - Colin Eberhardt's Adventures in .NET.
 
Follow me on Twitter - @ColinEberhardt
 
-
Follow on   Twitter   Google+

Comments and Discussions

 
QuestionVery nice PinmemberAmol_B10-Jan-12 23:20 
QuestionReally Nice PinmvpDave Kerr9-Jan-12 23:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.1411023.1 | Last Updated 8 Dec 2011
Article Copyright 2011 by Colin Eberhardt
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid