{"id":65,"date":"2010-12-19T14:35:49","date_gmt":"2010-12-19T09:05:49","guid":{"rendered":"http:\/\/techtwaddle.net\/?p=65"},"modified":"2011-01-26T14:43:05","modified_gmt":"2011-01-26T09:13:05","slug":"windows-phone-7-dragging-and-flicking-ui-controls","status":"publish","type":"post","link":"https:\/\/techtwaddle.co.in\/blog\/2010\/12\/19\/windows-phone-7-dragging-and-flicking-ui-controls\/","title":{"rendered":"Windows Phone 7 : Dragging and flicking UI controls"},"content":{"rendered":"<p>Who would want to flick and drag UI controls!? There  might not be many use cases but I think some concepts here are worthy of  a post.<\/p>\n<p>So we will create a simple silverlight application  for windows phone 7, containing a canvas element on which we\u2019ll place a  button control and an image and then, as the title says, drag and flick  the controls. Here\u2019s Mainpage.xaml,<\/p>\n<div>\n<div>\n<ol>\n<li>&lt;Grid x:Name=&#8221;LayoutRoot&#8221; Background=&#8221;Transparent&#8221;&gt;<\/li>\n<li> &lt;Grid.RowDefinitions&gt;<\/li>\n<li> &lt;RowDefinition Height=&#8221;Auto&#8221;\/&gt;<\/li>\n<li> &lt;RowDefinition Height=&#8221;*&#8221;\/&gt;<\/li>\n<li> &lt;\/Grid.RowDefinitions&gt;<\/li>\n<li><\/li>\n<li> &lt;!&#8211;TitlePanel contains the name of the application and page title&#8211;&gt;<\/li>\n<li> &lt;StackPanel x:Name=&#8221;TitlePanel&#8221; Grid.Row=&#8221;0&#8243; Margin=&#8221;12,17,0,28&#8243;&gt;<\/li>\n<li> &lt;TextBlock x:Name=&#8221;ApplicationTitle&#8221; Text=&#8221;KINETICS&#8221; Style=&#8221;{StaticResource PhoneTextNormalStyle}&#8221;\/&gt;<\/li>\n<li> &lt;TextBlock x:Name=&#8221;PageTitle&#8221; Text=&#8221;drag and flick&#8221; Margin=&#8221;9,-7,0,0&#8243; Style=&#8221;{StaticResource PhoneTextTitle1Style}&#8221;\/&gt;<\/li>\n<li> &lt;\/StackPanel&gt;<\/li>\n<li><\/li>\n<li> &lt;!&#8211;ContentPanel &#8211; place additional content here&#8211;&gt;<\/li>\n<li> &lt;Grid x:Name=&#8221;ContentPanel&#8221; Grid.Row=&#8221;1&#8243; &gt;<\/li>\n<li> &lt;Canvas x:Name=&#8221;MainCanvas&#8221; HorizontalAlignment=&#8221;Stretch&#8221; VerticalAlignment=&#8221;Stretch&#8221;&gt;<\/li>\n<li> &lt;Canvas.Background&gt;<\/li>\n<li> &lt;LinearGradientBrush StartPoint=&#8221;0 0&#8243; EndPoint=&#8221;0 1&#8243;&gt;<\/li>\n<li> &lt;GradientStop Offset=&#8221;0&#8243; Color=&#8221;Black&#8221;\/&gt;<\/li>\n<li> &lt;GradientStop Offset=&#8221;1.5&#8243; Color=&#8221;BlanchedAlmond&#8221;\/&gt;<\/li>\n<li> &lt;\/LinearGradientBrush&gt;<\/li>\n<li> &lt;\/Canvas.Background&gt;<\/li>\n<li> &lt;\/Canvas&gt;<\/li>\n<li> &lt;\/Grid&gt;<\/li>\n<li>&lt;\/Grid&gt;<\/li>\n<\/ol>\n<\/div>\n<\/div>\n<p>the second row in the main grid contains a canvas element, <span style=\"color: #000080;\">MainCanvas<\/span>,  with its horizontal and vertical alignment set to stretch so that it  occupies the entire grid. The canvas background is a linear gradient  brush starting with Black and ending with BlanchedAlmond. We\u2019ll add the  button and image control to this canvas at run time.<\/p>\n<p>Moving to Mainpage.xaml.cs the <span style=\"color: #000080;\">Mainpage<\/span> class contains the following members,<\/p>\n<div>\n<div>\n<ol>\n<li>public partial class MainPage : PhoneApplicationPage<\/li>\n<li>{<\/li>\n<li> Button FlickButton;<\/li>\n<li> Image FlickImage;<\/li>\n<li><\/li>\n<li> FrameworkElement ElemToMove = null;<\/li>\n<li> double ElemVelX, ElemVelY;<\/li>\n<li><\/li>\n<li> const double SPEED_FACTOR = 60;<\/li>\n<li><\/li>\n<li> DispatcherTimer timer;<\/li>\n<\/ol>\n<\/div>\n<\/div>\n<p><span style=\"color: #000080;\">FlickButton<\/span> and <span style=\"color: #000080;\">FlickImage<\/span> are the controls that we\u2019ll add to the canvas. <span style=\"color: #000080;\">ElemToMove<\/span>, <span style=\"color: #000080;\">ElemVelX<\/span> and <span style=\"color: #000080;\">ElemVelY<\/span> will be used by the timer callback to move the ui control. <span style=\"color: #000080;\">SPEED_FACTOR<\/span> is used to scale the velocities of ui controls.<\/p>\n<p>Here\u2019s the <span style=\"color: #000080;\">Mainpage<\/span> constructor,<\/p>\n<div>\n<div>\n<ol>\n<li>\/\/ Constructor<\/li>\n<li>public MainPage()<\/li>\n<li>{<\/li>\n<li> InitializeComponent();<\/li>\n<li><\/li>\n<li> AddButtonToCanvas();<\/li>\n<li><\/li>\n<li> AddImageToCanvas();<\/li>\n<li><\/li>\n<li> timer = new DispatcherTimer();<\/li>\n<li> timer.Interval = TimeSpan.FromMilliseconds(35);<\/li>\n<li> timer.Tick += new EventHandler(OnTimerTick);<\/li>\n<li>}<\/li>\n<\/ol>\n<\/div>\n<\/div>\n<p>We\u2019ll look at those <span style=\"color: #000080;\">AddButton<\/span> and <span style=\"color: #000080;\">AddImage<\/span> functions in a moment. The constructor initializes a timer which fires  every 35 milliseconds, this timer will be started after the flick  gesture completes with some inertia.<\/p>\n<p>Back to <span style=\"color: #000080;\">AddButton<\/span> and <span style=\"color: #000080;\">AddImage<\/span> functions,<\/p>\n<div>\n<div>\n<ol>\n<li>void AddButtonToCanvas()<\/li>\n<li>{<\/li>\n<li> LinearGradientBrush brush;<\/li>\n<li> GradientStop stop1, stop2;<\/li>\n<li><\/li>\n<li> Random rand = new Random(DateTime.Now.Millisecond);<\/li>\n<li><\/li>\n<li> FlickButton = new Button();<\/li>\n<li> FlickButton.Content = &#8220;&#8221;;<\/li>\n<li> FlickButton.Width = 100;<\/li>\n<li> FlickButton.Height = 100;<\/li>\n<li><\/li>\n<li> brush = new LinearGradientBrush();<\/li>\n<li> brush.StartPoint = new Point(0, 0);<\/li>\n<li> brush.EndPoint = new Point(0, 1);<\/li>\n<li><\/li>\n<li> stop1 = new GradientStop();<\/li>\n<li> stop1.Offset = 0;<\/li>\n<li> stop1.Color = Colors.White;<\/li>\n<li><\/li>\n<li> stop2 = new GradientStop();<\/li>\n<li> stop2.Offset = 1;<\/li>\n<li> stop2.Color = (Application.Current.Resources[&#8220;PhoneAccentBrush&#8221;] as SolidColorBrush).Color;<\/li>\n<li><\/li>\n<li> brush.GradientStops.Add(stop1);<\/li>\n<li> brush.GradientStops.Add(stop2);<\/li>\n<li><\/li>\n<li> FlickButton.Background = brush;<\/li>\n<li><\/li>\n<li> Canvas.SetTop(FlickButton, rand.Next(0, 400));<\/li>\n<li> Canvas.SetLeft(FlickButton, rand.Next(0, 200));<\/li>\n<li><\/li>\n<li> MainCanvas.Children.Add(FlickButton);<\/li>\n<li><\/li>\n<li> \/\/subscribe to events<\/li>\n<li> FlickButton.ManipulationDelta += new EventHandler&lt;ManipulationDeltaEventArgs&gt;(OnManipulationDelta);<\/li>\n<li> FlickButton.ManipulationCompleted += new EventHandler&lt;ManipulationCompletedEventArgs&gt;(OnManipulationCompleted);<\/li>\n<li>}<\/li>\n<\/ol>\n<\/div>\n<\/div>\n<p>this function is basically glorifying a simple task.  After creating the button and setting its height and width, its  background is set to a linear gradient brush. The direction of the  gradient is from top towards bottom and notice that the second stop  color is the <span style=\"color: #000080;\"><em>PhoneAccentColor<\/em><\/span>, which changes along with the theme of the device. The line,<\/p>\n<p>stop2.Color = (Application.Current.Resources[&#8220;PhoneAccentBrush&#8221;] as SolidColorBrush).Color;<\/p>\n<p>does the magic of extracting the <span style=\"color: #000080;\">PhoneAccentBrush<\/span> from application\u2019s resources, getting its color and assigning it to the gradient stop.<\/p>\n<p><span style=\"color: #000080;\">AddImage<\/span> function is straight forward in comparison,<\/p>\n<div>\n<div>\n<ol>\n<li>void AddImageToCanvas()<\/li>\n<li>{<\/li>\n<li> Random rand = new Random(DateTime.Now.Millisecond);<\/li>\n<li><\/li>\n<li> FlickImage = new Image();<\/li>\n<li> FlickImage.Source = new BitmapImage(new Uri(&#8220;\/images\/Marble.png&#8221;, UriKind.Relative));<\/li>\n<li><\/li>\n<li> Canvas.SetTop(FlickImage, rand.Next(0, 400));<\/li>\n<li> Canvas.SetLeft(FlickImage, rand.Next(0, 200));<\/li>\n<li><\/li>\n<li> MainCanvas.Children.Add(FlickImage);<\/li>\n<li><\/li>\n<li> \/\/subscribe to events<\/li>\n<li> FlickImage.ManipulationDelta += new EventHandler&lt;ManipulationDeltaEventArgs&gt;(OnManipulationDelta);<\/li>\n<li> FlickImage.ManipulationCompleted += new EventHandler&lt;ManipulationCompletedEventArgs&gt;(OnManipulationCompleted);<\/li>\n<li>}<\/li>\n<\/ol>\n<\/div>\n<\/div>\n<p>The <span style=\"color: #000080;\">ManipulationDelta<\/span> and <span style=\"color: #000080;\">ManipulationCompleted<\/span> handlers are same for both the button and the image.<\/p>\n<p><span style=\"color: #000080;\">OnManipulationDelta()<\/span> should look familiar, a similar implementation was used in the <a href=\"http:\/\/geekswithblogs.net\/TechTwaddle\/archive\/2010\/11\/22\/windows-phone-7--ui-control-boundaries.aspx\">previous post<\/a>,<\/p>\n<div>\n<div>\n<ol>\n<li>void OnManipulationDelta(object sender, ManipulationDeltaEventArgs args)<\/li>\n<li>{<\/li>\n<li> FrameworkElement Elem = sender as FrameworkElement;<\/li>\n<li><\/li>\n<li> double Left = Canvas.GetLeft(Elem);<\/li>\n<li> double Top = Canvas.GetTop(Elem);<\/li>\n<li><\/li>\n<li> Left += args.DeltaManipulation.Translation.X;<\/li>\n<li> Top += args.DeltaManipulation.Translation.Y;<\/li>\n<li><\/li>\n<li> \/\/check for bounds<\/li>\n<li> if (Left &lt; 0)<\/li>\n<li> {<\/li>\n<li> Left = 0;<\/li>\n<li> }<\/li>\n<li> else if (Left &gt; (MainCanvas.ActualWidth &#8211; Elem.ActualWidth))<\/li>\n<li> {<\/li>\n<li> Left = MainCanvas.ActualWidth &#8211; Elem.ActualWidth;<\/li>\n<li> }<\/li>\n<li><\/li>\n<li> if (Top &lt; 0)<\/li>\n<li> {<\/li>\n<li> Top = 0;<\/li>\n<li> }<\/li>\n<li> else if (Top &gt; (MainCanvas.ActualHeight &#8211; Elem.ActualHeight))<\/li>\n<li> {<\/li>\n<li> Top = MainCanvas.ActualHeight &#8211; Elem.ActualHeight;<\/li>\n<li> }<\/li>\n<li><\/li>\n<li> Canvas.SetLeft(Elem, Left);<\/li>\n<li> Canvas.SetTop(Elem, Top);<\/li>\n<li>}<\/li>\n<\/ol>\n<\/div>\n<\/div>\n<p>all it does is calculate the control\u2019s position, check for bounds and then set the top and left of the control.<\/p>\n<p><span style=\"color: #000080;\">OnManipulationCompleted()<\/span> is more interesting because here we need to check if the gesture  completed with any inertia and if it did, start the timer and continue  to move the ui control until it comes to a halt slowly,<\/p>\n<div>\n<div>\n<ol>\n<li>void OnManipulationCompleted(object sender, ManipulationCompletedEventArgs args)<\/li>\n<li>{<\/li>\n<li> FrameworkElement Elem = sender as FrameworkElement;<\/li>\n<li><\/li>\n<li> if (args.IsInertial)<\/li>\n<li> {<\/li>\n<li> ElemToMove = Elem;<\/li>\n<li><\/li>\n<li> Debug.WriteLine(&#8220;Linear VelX:{0:0.00}\u00a0 VelY:{1:0.00}&#8221;, args.FinalVelocities.LinearVelocity.X,<\/li>\n<li> args.FinalVelocities.LinearVelocity.Y);<\/li>\n<li><\/li>\n<li> ElemVelX = args.FinalVelocities.LinearVelocity.X \/ SPEED_FACTOR;<\/li>\n<li> ElemVelY = args.FinalVelocities.LinearVelocity.Y \/ SPEED_FACTOR;<\/li>\n<li><\/li>\n<li> timer.Start();<\/li>\n<li> }<\/li>\n<li>}<\/li>\n<\/ol>\n<\/div>\n<\/div>\n<p><span style=\"color: #000080;\">ManipulationCompletedEventArgs<\/span> contains a member, <span style=\"color: #000080;\">IsInertial<\/span>, which is set to true if the manipulation was completed with some inertia. <span style=\"color: #000080;\">args.FinalVelocities.LinearVelocity.X<\/span> and <span style=\"color: #000080;\">.Y<\/span> will contain the velocities along the X and Y axis. We need to scale  down these values so they can be used to increment the ui control\u2019s  position sensibly. A reference to the ui control is stored in <span style=\"color: #000080;\">ElemToMove<\/span> and the velocities are stored as well, these will be used in the timer  callback to access the ui control. And finally, we start the timer.<\/p>\n<p>The timer callback function is as follows,<\/p>\n<div>\n<div>\n<ol>\n<li>void OnTimerTick(object sender, EventArgs e)<\/li>\n<li>{<\/li>\n<li> if (null != ElemToMove)<\/li>\n<li> {<\/li>\n<li> double Left, Top;<\/li>\n<li> Left = Canvas.GetLeft(ElemToMove);<\/li>\n<li> Top = Canvas.GetTop(ElemToMove);<\/li>\n<li><\/li>\n<li> Left += ElemVelX;<\/li>\n<li> Top += ElemVelY;<\/li>\n<li><\/li>\n<li> \/\/check for bounds<\/li>\n<li> if (Left &lt; 0)<\/li>\n<li> {<\/li>\n<li> Left = 0;<\/li>\n<li> ElemVelX *= -1;<\/li>\n<li> }<\/li>\n<li> else if (Left &gt; (MainCanvas.ActualWidth &#8211; ElemToMove.ActualWidth))<\/li>\n<li> {<\/li>\n<li> Left = MainCanvas.ActualWidth &#8211; ElemToMove.ActualWidth;<\/li>\n<li> ElemVelX *= -1;<\/li>\n<li> }<\/li>\n<li><\/li>\n<li> if (Top &lt; 0)<\/li>\n<li> {<\/li>\n<li> Top = 0;<\/li>\n<li> ElemVelY *= -1;<\/li>\n<li> }<\/li>\n<li> else if (Top &gt; (MainCanvas.ActualHeight &#8211; ElemToMove.ActualHeight))<\/li>\n<li> {<\/li>\n<li> Top = MainCanvas.ActualHeight &#8211; ElemToMove.ActualHeight;<\/li>\n<li> ElemVelY *= -1;<\/li>\n<li> }<\/li>\n<li><\/li>\n<li> Canvas.SetLeft(ElemToMove, Left);<\/li>\n<li> Canvas.SetTop(ElemToMove, Top);<\/li>\n<li><\/li>\n<li> \/\/reduce x,y velocities gradually<\/li>\n<li> ElemVelX *= 0.9;<\/li>\n<li> ElemVelY *= 0.9;<\/li>\n<li><\/li>\n<li> \/\/when velocities become too low, break<\/li>\n<li> if (Math.Abs(ElemVelX) &lt; 1.0 &amp;&amp; Math.Abs(ElemVelY) &lt; 1.0)<\/li>\n<li> {<\/li>\n<li> timer.Stop();<\/li>\n<li> ElemToMove = null;<\/li>\n<li> }<\/li>\n<li> }<\/li>\n<li>}<\/li>\n<\/ol>\n<\/div>\n<\/div>\n<p>if <span style=\"color: #000080;\">ElemToMove<\/span> is not null, we get the  top and left values of the control and increment the values with their X  and Y velocities. Check for bounds, and if the control goes out of  bounds we reverse its velocity. Towards the end, the velocities are  reduced by 10% every time the timer callback is called, and if the  velocities reach too low values the timer is stopped and <span style=\"color: #000080;\">ElemToMove<\/span> is made null.<\/p>\n<p>Here\u2019s a short video of the program, the video is a little dodgy because my display driver <a href=\"http:\/\/social.msdn.microsoft.com\/Forums\/en-US\/windowsphone7series\/thread\/fa447c95-496e-431d-88a7-b0a76d177c92\">refuses to run the animations smoothly<\/a>. The flicks aren\u2019t always recognised but the program should run well on an actual device (or a pc with better configuration),<\/p>\n<p><object width=\"480\" height=\"385\"><param value=\"http:\/\/www.youtube.com\/v\/nlqULtosHlw?fs=1&amp;hl=en_US&amp;color1=0x3a3a3a&amp;color2=0x999999\" name=\"movie\" \/><param value=\"true\" name=\"allowFullScreen\" \/><param value=\"always\" name=\"allowscriptaccess\" \/><\/object><\/p>\n<p>You can download the source code from here: <a href=\"http:\/\/cid-65187cfbc4ac6ad2.office.live.com\/self.aspx\/.Public\/SourceCode\/ButtonDragAndFlick.zip\">ButtonDragAndFlick.zip<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Who would want to flick and drag UI controls!? There might not be many use cases but I think some concepts here are worthy of a post. So we will create a simple silverlight application for windows phone 7, containing a canvas element on which we\u2019ll place a button control and an image and then, &hellip; <a href=\"https:\/\/techtwaddle.co.in\/blog\/2010\/12\/19\/windows-phone-7-dragging-and-flicking-ui-controls\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Windows Phone 7 : Dragging and flicking UI controls<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"spay_email":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false},"categories":[1],"tags":[],"jetpack_featured_media_url":"","jetpack_publicize_connections":[],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p1ktFF-13","_links":{"self":[{"href":"https:\/\/techtwaddle.co.in\/blog\/wp-json\/wp\/v2\/posts\/65"}],"collection":[{"href":"https:\/\/techtwaddle.co.in\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/techtwaddle.co.in\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/techtwaddle.co.in\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/techtwaddle.co.in\/blog\/wp-json\/wp\/v2\/comments?post=65"}],"version-history":[{"count":3,"href":"https:\/\/techtwaddle.co.in\/blog\/wp-json\/wp\/v2\/posts\/65\/revisions"}],"predecessor-version":[{"id":72,"href":"https:\/\/techtwaddle.co.in\/blog\/wp-json\/wp\/v2\/posts\/65\/revisions\/72"}],"wp:attachment":[{"href":"https:\/\/techtwaddle.co.in\/blog\/wp-json\/wp\/v2\/media?parent=65"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/techtwaddle.co.in\/blog\/wp-json\/wp\/v2\/categories?post=65"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/techtwaddle.co.in\/blog\/wp-json\/wp\/v2\/tags?post=65"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}