Click here to Skip to main content
11,484,941 members (78,151 online)
Click here to Skip to main content

Tagged as

Scrollable Friction Canvas For Silverlight

, 9 Apr 2009 CPOL 13.7K 7
Rate this:
Please Sign up or sign in to vote.
A while back I published a post about creating a friction enabled scrolling canvas in WPF (the old post can be found at http://sachabarber.net/?p=225), which I thought was way cool. It turns out that I was not the only one that thought this, and one of my WPF Buddies and fellow WPF Disciples Jeremia

A while back I published a post about creating a friction enabled scrolling canvas in WPF (the old post can be found at http://sachabarber.net/?p=225), which I thought was way cool. It turns out that I was not the only one that thought this, and one of my WPF Buddies and fellow WPF Disciples Jeremiah Morrill thought it was so cool that he turned it into a Silverlight Content control. Thoughtful old Jerimiah even sent me the code back, which I think is awesome of him.

As a result I thought I would let you all have it. So here goes.

This is what Jer has done, here is the actual ContentControl, which has my friction stuff in it

   1:  using System;
   2:  using System.Windows;
   3:  using System.Windows.Controls;
   4:  using System.Windows.Input;
   5:  using System.Windows.Threading;
   6:  
   7:  namespace FlickScrollerApp
   8:  {
   9:      [TemplatePart(Name = “PART_ScrollViewer”,
             Type = typeof(ScrollViewer))]
  10:      public class FlickScrollView : ContentControl
  11:      {
  12:          private readonly DispatcherTimer m_animationTimer =
  13:          new DispatcherTimer();
  14:          private double m_friction;
  15:          private Point m_currentMousePos;
  16:          private Point m_previousPoint;
  17:          private Point m_scrollStartOffset = new Point();
  18:          private Point m_scrollStartPoint;
  19:          private Point m_scrollTarget = new Point();
  20:          private Vector m_velocity;
  21:          private ScrollViewer scrollViewer;
  22:  
  23:          public FlickScrollView()
  24:          {
  25:              DefaultStyleKey = typeof(FlickScrollView);
  26:  
  27:              m_friction = 0.98;
  28:  
  29:              m_animationTimer.Interval = new
                     TimeSpan(0, 0, 0, 0, 20);
  30:              m_animationTimer.Tick += HandleWorldTimerTick;
  31:              m_animationTimer.Start();
  32:  
  33:              MouseMove += MouseMoveHandler;
  34:              MouseLeftButtonUp += MouseLeftButtonUpHandler;
  35:              MouseLeftButtonDown += MouseLeftButtonDownHandler;
  36:          }
  37:  
  38:          private bool IsMouseCaptured { get; set; }
  39:  
  40:          public double Friction
  41:          {
  42:              get { return 1.0 - m_friction; }
  43:              set { m_friction =
                       Math.Min(Math.Max(1.0 - value, 0), 1.0); }
  44:          }
  45:  
  46:          public override void OnApplyTemplate()
  47:          {
  48:              base.OnApplyTemplate();
  49:              scrollViewer = GetTemplateChild(“PART_ScrollViewer”)
                      as ScrollViewer;
  50:          }
  51:  
  52:          private void MouseLeftButtonDownHandler(object sender,
  53:          MouseButtonEventArgs e)
  54:          {
  55:              if (scrollViewer == null)
  56:                  return;
  57:  
  58:              m_scrollStartPoint = e.GetPosition(this);
  59:              m_scrollStartOffset.X = scrollViewer.HorizontalOffset;
  60:              m_scrollStartOffset.Y = scrollViewer.VerticalOffset;
  61:  
  62:              CaptureMouse();
  63:  
  64:              IsMouseCaptured = true;
  65:          }
  66:  
  67:          private void MouseLeftButtonUpHandler(object sender,
  68:          MouseButtonEventArgs e)
  69:          {
  70:              if (!IsMouseCaptured)
  71:                  return;
  72:  
  73:              ReleaseMouseCapture();
  74:              IsMouseCaptured = false;
  75:          }
  76:  
  77:          private void MouseMoveHandler(object sender, MouseEventArgs e)
  78:          {
  79:              if (scrollViewer == null)
  80:                  return;
  81:  
  82:              m_currentMousePos = e.GetPosition(this);
  83:  
  84:              if (IsMouseCaptured)
  85:              {
  86:                  Point currentPoint = e.GetPosition(this);
  87:  
  88:                  // Determine the new amount to scroll.
  89:                  var delta = new Point(m_scrollStartPoint.X -
  90:              currentPoint.X, m_scrollStartPoint.Y - currentPoint.Y);
  91:  
  92:                  m_scrollTarget.X = m_scrollStartOffset.X + delta.X;
  93:                  m_scrollTarget.Y = m_scrollStartOffset.Y + delta.Y;
  94:  
  95:                  // Scroll to the new position.
  96:                  scrollViewer.ScrollToHorizontalOffset(m_scrollTarget.X);
  97:                  scrollViewer.ScrollToVerticalOffset(m_scrollTarget.Y);
  98:              }
  99:          }
 100:  
 101:          private void HandleWorldTimerTick(object sender, EventArgs e)
 102:          {
 103:              if (scrollViewer == null)
 104:                  return;
 105:  
 106:              if (IsMouseCaptured)
 107:              {
 108:                  Point currentPoint = m_currentMousePos;
 109:                  m_velocity.X = m_previousPoint.X - currentPoint.X;
 110:                  m_velocity.Y = m_previousPoint.Y - currentPoint.Y;
 111:                  m_previousPoint = currentPoint;
 112:              }
 113:              else
 114:              {
 115:                  if (m_velocity.Length > 1)
 116:                  {
 117:                      scrollViewer.ScrollToHorizontalOffset(m_scrollTarget.X);
 118:                      scrollViewer.ScrollToVerticalOffset(m_scrollTarget.Y);
 119:                      m_scrollTarget.X += m_velocity.X;
 120:                      m_scrollTarget.Y += m_velocity.Y;
 121:                      m_velocity *= m_friction;
 122:                  }
 123:              }
 124:          }
 125:      }
 126:  }

And here is how you would use it in XAML

   1:  <UserControl x:Class=”FlickScrollerApp.MainPage”
   2:               xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
   3:               xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
   4:               xmlns:FlickScrollerApp=”clr-namespace:FlickScrollerApp”
   5:               Width=”400″
   6:               Height=”300″>
   7:      <Grid x:Name=”LayoutRoot”
   8:            Background=”White”>
   9:          <FlickScrollerApp:FlickScrollView>
  10:              <StackPanel>
  11:                  <Rectangle Fill=”Red”
  12:                             Width=”400″
  13:                             Height=”200″
  14:                             IsHitTestVisible=”False” />
  15:                  <Rectangle Fill=”Blue”
  16:                             Width=”400″
  17:                             Height=”200″
  18:                             IsHitTestVisible=”False” />
  19:                  <Rectangle Fill=”Red”
  20:                             Width=”400″
  21:                             Height=”200″
  22:                             IsHitTestVisible=”False” />
  23:                  <Rectangle Fill=”Blue”
  24:                             Width=”400″
  25:                             Height=”200″
  26:                             IsHitTestVisible=”False” />
  27:                  <Rectangle Fill=”Red”
  28:                             Width=”400″
  29:                             Height=”200″
  30:                             IsHitTestVisible=”False” />
  31:                  <Rectangle Fill=”Blue”
  32:                             Width=”400″
  33:                             Height=”200″
  34:                             IsHitTestVisible=”False” />
  35:                  <Rectangle Fill=”Red”
  36:                             Width=”400″
  37:                             Height=”200″
  38:                             IsHitTestVisible=”False” />
  39:              </StackPanel>
  40:          </FlickScrollerApp:FlickScrollView>
  41:      </Grid>
  42:  </UserControl>

And another nice thing Jer has done is provide a Theme

   1:  <ResourceDictionary xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
   2:                      xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
   3:                      xmlns:FlickScrollerApp=”clr-namespace:FlickScrollerApp”>
   4:      <Style TargetType=”FlickScrollerApp:FlickScrollView”>
   5:          <Setter Property=”IsEnabled”
   6:                  Value=”true” />
   7:          <Setter Property=”HorizontalContentAlignment”
   8:                  Value=”Left” />
   9:          <Setter Property=”VerticalContentAlignment”
  10:                  Value=”Top” />
  11:          <Setter Property=”Cursor”
  12:                  Value=”Arrow” />
  13:          <Setter Property=”Background”
  14:                  Value=”#00000000″ />
  15:          <Setter Property=”Template”>
  16:              <Setter.Value>
  17:                  <ControlTemplate TargetType=”FlickScrollerApp:FlickScrollView”>
  18:                      <Border Background=”{TemplateBinding Background}”
  19:                              BorderBrush=”{TemplateBinding BorderBrush}”
  20:                              BorderThickness=”{TemplateBinding BorderThickness}”
  21:                              CornerRadius=”2″>
  22:                          <ScrollViewer x:Name=”PART_ScrollViewer”>
  23:                              <ContentControl Content=”{TemplateBinding Content}”
  24:                                ContentTemplate=”{TemplateBinding ContentTemplate}”
  25:                                Cursor=”{TemplateBinding Cursor}”
  26:                                HorizontalAlignment=”{TemplateBinding HorizontalAlignment}”
  27:                                HorizontalContentAlignment=
  28:                  “{TemplateBinding HorizontalContentAlignment}”
  29:                                FontFamily=”{TemplateBinding FontFamily}”
  30:                                FontSize=”{TemplateBinding FontSize}”
  31:                                FontStretch=”{TemplateBinding FontStretch}”
  32:                                Foreground=”{TemplateBinding Foreground}”
  33:                                Margin=”{TemplateBinding Padding}”
  34:                                VerticalAlignment=”{TemplateBinding VerticalAlignment}”
  35:                                VerticalContentAlignment=
  36:                  “{TemplateBinding VerticalContentAlignment}” />
  37:                          </ScrollViewer>
  38:                      </Border>
  39:                  </ControlTemplate>
  40:              </Setter.Value>
  41:          </Setter>
  42:      </Style>
  43:  </ResourceDictionary>

Here is a small Silverlight 3 project that demonstrates this.

flickscrollerapp.zip

Cheers Jer, you rock

License

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

Share

About the Author

Sacha Barber
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)

- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence

Both of these at Sussex University UK.

Award(s)

I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2015
  • Codeproject MVP 2015
  • Microsoft C# MVP 2014
  • Codeproject MVP 2014
  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

Comments and Discussions

 
GeneralHorizontal scrolling Pin
MasterX_Group19-Nov-10 22:48
memberMasterX_Group19-Nov-10 22:48 
GeneralRe: Horizontal scrolling Pin
Sacha Barber19-Nov-10 23:15
mvpSacha Barber19-Nov-10 23:15 

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
Web04 | 2.8.150520.1 | Last Updated 9 Apr 2009
Article Copyright 2009 by Sacha Barber
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid