XAML Playground
about XAML and other Amenities

Taking advantage of combining different streams using Reactive Extension's:

2011-04-04T16:18:45+01:00 by Andrea Boschin

One interesting feature of Reactive Extensions is the combining of Observables. There are a number of extension methods made to combine two or more streams; Amb, Concat, SelectMany, Merge, Zip, CombineLatest, all these methods are made to take, multiple and non necessarily omogeneous, streams and combine them in a unique resulting stream based on different rules. Here a brief resume of the rules applied from every method

Amb returns the stream that start providing values by first
Concat chain two streams one to the end of the other and create a single output
SelectMany Returns every value from the second stream for each value from the first
Merge returns the two streams merged basing of when each source returns its value
Zip returns values from one stream paired with values from another, only when a couple is available.
CombineLatest Combine two streams returning always the latest from both, for each occurrence of a value.

 

Understanding the meaning of each method is really difficult if you do not make some simple experiment, but this is out of the scope of this post. Now I would like to show the meaning of "combining two streams" with a real example that show how a little change in the previous mouse trail example can give a great difference in terms of functions.

In my last example I used the TrailWithCount and TrailWithTime methods to catch MouseMove events to draw a polyline on the plugin that il the trail of the mouse pointer. In the example you have seen the trail shortens while the mouse was moving but when the mouse stops also the trail stops. Now I want to change the example to let the trail shorten to zero length when the mouse stops moving.

To achieve this result I need to have a timer that continues to record the current position for the mouse when it stops. For this purpose I can use the static method Obsevable.Interval(timespan) that is able to generate a stream of events at the given interval of time. Here is the two lines I have to add to the previous example.

   1: Observable.FromEvent<MouseEventHandler, MouseEventArgs>(
   2:     ev => new MouseEventHandler(ev),
   3:     ev => this.LayoutRoot.MouseMove += ev,
   4:     ev => this.LayoutRoot.MouseMove -= ev)
   5:     .CombineLatest(Observable.Interval(TimeSpan.FromMilliseconds(25)), (a, b) => a)
   6:     .ObserveOnDispatcher()
   7:     .Select(o => o.EventArgs.GetPosition(this.LayoutRoot))
   8:     .TrailWithCount(100)
   9:     .Subscribe(DrawLine);

the CombineLatest method gets events from the mouse and from the time interval (this regularly every 25 milliseconds) and using the selector lambda it takes from the combined stream only the mouse events. Every time an interval expire the combined value will contain an integer (the number of intervals from the start) and the latest mouse event. When the mouse stops moving the stream from the MouseMove also stops to provide values but the CombineLatest method will replicate the latest value taken for every interval elapsed. So the trail will be feeded with the latest position and the visual effect will be the shorten of the trail until it reaches the current position of the mouse pointer.

The ObserveOnDispatched method is required because the Observable.Interval method implies the use of a separate thread so when we get the values we are in this thread and we need to marshall back to the UI thread. This method does the trick. Here is the result:

Get Microsoft Silverlight

Demo from Italy Remix 2010

2010-07-01T22:44:49+01:00 by Andrea Boschin

Last June 23 I had the pleasure of presenting an introductive session about Silverlight at . During the presentation, included in the “jump start” track, I’ve illustrated the basic capabilities of Silverlight using a simple application that consume a RSS feed from the . The feed give news about all the Earthquakes happening on the world surface and all them are geo tagged.

So, during the session, I’ve showed the application growing from a simple reader to a complex and effective tool to display the earthquakes on a map, using the Silverlight control for Bing Maps. The people was impressed by the application, so I decided to publish the sample on my blog, hoping it can become a good starting point for people wants to approach the Silverlight development.

The application is really simple, without any surprise for skilled people, but it show the main points, from where someone must start. You can see layout, shapes, brushes, animations, projections, network access, syndication and data binding, but also show the power of an Out of browser application and the customization of the window chrome. I hope you enjoy the sample.

Download: code | live demo

Chromeless Window for OOB applications in Silverlight 4.0 RC

2010-03-15T19:07:07+01:00 by Andrea Boschin

I think all of you are aware of the new useful features of Silverlight 4.0 beta released last November. I'm referringUntitled to a bunch of new improvements, affecting the out of browser applications, starting from the full-trust capabilities to the new Notification Window, and some little changes to the configuration of the window. The new release candidate of Silverlight 4.0 bring some news to the out of browser applications.

Until now we have a very little control over the window containing the application; we can configure the size and the positon on the screen and it is not possible to change them at runtime. With Silverlight 4.0 the Application class gain a new MainWindow proprty that expose a full set of tools to operate with the window. But this is not all the story. Using the project property we can also configure the window to be borderless and this let us draw our own chrome and manage window moving and resizing at runtime.

win The figure on the left show the configuration of the Window Style. It is available into the Out of browser settings window. Using NoBorder we can completely remove the default chrome of the window. Optionally we can also specify to have Round corners but there is not any configuration about the corner radius.

In the example attached to the end of this article I've created a simple control we can use to give a custom chrome to the window. The control has a template to customize the look and feel of the chromw and a buch of properties to define colors, and other aspects of the chrome. In the next paragraphs of this article I will show you how the control is built and how Silverlight let use easily customize the chrome in the release candidate bits.

The ApplicationWindow control

When we create a Silverlight application we usually define the MainPage.xaml as a UserControl, and this let us specify the markup of the page easily. Creating the ApplicationWindow control I decided to sobstitute it to the common UserControl so the control is defined as a ContentControl and we can change the markup like the code in this snippet:

   1: <controls:ApplicationWindow x:Class="SilverlightPlayground.GenericWindow.MainPage"
   2:                             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:                             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:                             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   5:                             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   6:                             xmlns:controls="clr-namespace:SilverlightPlayground.Controls;assembly=SilverlightPlayground.Controls"
   7:                             Title="Tiny Browser"
   8:                             mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400">
   9:     <Grid x:Name="LayoutRoot" Background="WhiteSmoke">
  10:  
  11:     </Grid>
  12: </controls:ApplicationWindow>

The control is a normal Templated Control and in the generic.xaml I've specified the default aspect of the window chrome. Some of the properties of the elements inside the template have been binded to the properties of the ApplicationWindow control so it is simple to change the Border color, the background, the font etc. Some elements has been defined as parts so I can attach some events and add the expected behavior to the window. When the user drag the chrome the window has to move on the screen and when the user drags the corner the window has to be resized.

The release candidate of Silverlight give us two methods doing the great part of the work. They ad DragResize and DragMove. In the control I attach the MouseLeftButtonDown event and in the handler I call one of these method to start the corresponding action. Here is the code:

   1: void Chrome_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
   2: {
   3:     if (Application.Current.IsRunningOutOfBrowser && Application.Current.HasElevatedPermissions)
   4:         Application.Current.MainWindow.DragMove();
   5: }
   6:  
   7: void ResizeHandle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
   8: {
   9:     if (Application.Current.IsRunningOutOfBrowser && Application.Current.HasElevatedPermissions)
  10:         Application.Current.MainWindow.DragResize(WindowResizeEdge.BottomRight);
  11: }

The methods are so simple we really do not need to make any other action. After starting the action it detect the mouse and terminate the drag when the user release the button.

There is some other behaviors to implement. In the top right corner some buttons let the user close the window and operate like common windows minimizing and maximizing it. The MainWindow property has all the mehods and properties we need to make these buttons working. Here is some other code:

   1: void CloseButton_Click(object sender, RoutedEventArgs e)
   2: {
   3:     if (Application.Current.IsRunningOutOfBrowser && Application.Current.HasElevatedPermissions && !args.Cancel)
   4:         Application.Current.MainWindow.Close();
   5: }
   6:  
   7: void MaximizeButton_Click(object sender, RoutedEventArgs e)
   8: {
   9:     if (Application.Current.IsRunningOutOfBrowser && Application.Current.HasElevatedPermissions)
  10:     {
  11:         if (Application.Current.MainWindow.WindowState == WindowState.Normal)
  12:             Application.Current.MainWindow.WindowState = WindowState.Maximized;
  13:         else
  14:             Application.Current.MainWindow.WindowState = WindowState.Normal;
  15:     }
  16: }
  17:  
  18: void MinimizeButton_Click(object sender, RoutedEventArgs e)
  19: {
  20:     if (Application.Current.IsRunningOutOfBrowser && Application.Current.HasElevatedPermissions)
  21:         Application.Current.MainWindow.WindowState = WindowState.Minimized;
  22: }

The video at the end of the article show how the window appear. The control is almost complete to emulate the common windows but there is some other features we can use to manage the window:

Top, Left, Width & Height can be user programmatically to change the size of the window at runtime, Activate bring the window in front of the other window and finally the TopMost property can make it standing on top of other windows.

Source: SilverlightPlayground.GenericWindow.zip
Video: ChromelessWindow.wmv

What's new about Out Of Browser in Silverlight 3.0 RTW

2009-07-10T17:45:00+01:00 by Andrea Boschin

Some months ago, a couple of minutes after the first beta of Silverlight has been released, I've posted an article explaining how to configure the new Out of Browser feature in Silverlight 3.0. Now, just after the release of the final bits, I need to return back on the argument because something has changed during this time due to additional features and modification to the API I've explained.

What has changed and What has been added.

There is not any substantial change to the functionality of the OOB applications. As you may expect it is still available a context menu to detach the application from the browser - but this operation now has changed its name from "detach" to "install" - and there is a way to uninstall the application again with the same context menu. While the name of the operation has changed now the method and events related to is has also changed the name following this schema:

Previous Current
public bool Detach(); public bool Install();
public bool RunningOffline; public bool RunningOutOfBrowser;
public event EventHandler ExecutionStateChanged; public event EventHandler InstallStateChanged;
public enum ExecutionStates
{
    RunningOnline,
    Detaching,
    Detached,
    DetachedUpdatesAvailable,
    DetachFailed
}
public enum InstallState
{
    NotInstalled,
    Installing,
    Installed,
    InstallFailed
}


As you may have noticed one important enumeration member - DetachedUpdatesAvailable - has been removed but this feature has not been lost. Now there a couple of API to support the application updates giving a bit more control in the update flow. We can choice when check for updates using the CheckAndDownloadUpdateAsync() method and getting notified if the update process succeded by the event CheckAndDownloadUpdateCompleted. Here is how to check for updates:

   1: Application.Current.CheckAndDownloadUpdateCompleted +=
   2:     (s, e) =>
   3:     {
   4:         if (e.UpdateAvailable)
   5:             MessageBox.Show(@"Updates have been downloaded. 
   6:                               Please restart the application to 
   7:                               apply this updates.");
   8:     };
   9:  
  10: Application.Current.CheckAndDownloadUpdateAsync();

Once you have started the process there isn't any way to stop it or to rollback any downloaded update. You can only notify the user that the updates has been downloaded and that this updates will be available the next time the application will be started.

The most significant change to the Out-of-browser is in the feature configuration. Now the settings are placed in a specific file you can find into the Properties folder in the Solution Explorer. The file OutOfBrowserSettings.xml contains the same properties of the beta with some slight changes:

1. The Title property has been moved to the WindowSettings section
2. Width and Height properties has been added to configure the initial size of the window
3. The Icon size has to be specified using a comma separated value notation

Now Visual Studio 2008 can directly manage this properties using an Out-of-Browser Settings button in the Silverlight properties tab so there is no need to directly edit the xml file.

Out of browser configuration You have to be aware that there is not full control over plugin features while it is installed on the machine. The sole feature you can activate i the usage of GPU acceleration, but there isn't a way to change the backgroun color of the plugin. Also remember that the usage of html bridge is forbidden while in oob mode.

Updated Sample

I've just changed the downloadable sample attached to my previous article and I give you agan the link here to have a fully functional sample on how to configure and use the out of browser.

Download code: Elite.Silverlight3.ToDoList.zip (2.02 MB)

Demo Video: OutOfBrowserExperience.wmv (3.5 MB)

Silverlight 3.0 RTW: An universal MouseWheelScrolling behavior

2009-07-10T17:45:00+01:00 by Andrea Boschin

Silverlight 3.0 RTW introduces a new event many people has asked for in the last months, the MouseWheel event. Handling this event is pretty simple while it simply raise and event that take a Delta to the developer with a positive or negative value according to the direction and the amount of the scrolling.

Showing an sample about MouseWheel take a few lines of code and is unuseful while I think many people can simply experiment and understant how it works in a few minutes. So I decided to merge this sample with some words about the new Behaviors introduced with Expression Blend.

My focus in this post is to show how to create a Behavior,  and using the MouseWheel event, add to all the scrollable controls the capability to scroll using the Mouse wheel.

What is a Behavior?

Some of you may have already used the Behaviors in the ASP.NET AJAX framework. The simple answer to the question of this paragraph is: "They are a Silverlight implementation of the ASP.NET AJAX semantics that allow to create reusable and attachable behaviors to HTML controls". You may find the origin of Silverlight Behaviors in an example posted by Nikhil Kothari during the May 2008.

While the simple answer is very clear and let you understand the concept under Behaviors we have to explore them more deeply to understant how to create a behavior and let it available to our projects.

The beta of Blend 3 introduces the concept of behavior into the Blend interface. There are some built-in behaviors we can simply drag on the design surface to give a new life to our graphical elements. Into the Asset folder, where usually we find controls, effects, resources and other thing, there is a new "behaviors" sheet like in the image I attached here on the right. 

With Expression Blend 3.0 many types of behaviors have been introduced. Behavior<T> is the most simple flavour that apply to a DependencyObject (the generic T) and handle events and other aspects from the source controls. A behavior can simply modify the aspect of a control, adding elements, changing the properties, or can handle one or more events to add some new features. The MouseDragElementBehavior is an example of it. Simply it attach Mouse events and let the element to be dragged into the page.

Writing a behavior

Writing a behavior is a pretty simple task. A behavior is a class extending Behavior<T> so the first thing to do is referencing the assemblies Microsoft.Expression.Interactions.dll and System.Windows.Interactivity.dll. from the following folder:

C:\Program Files\Microsoft SDKs\Expression\Blend 3\Interactivity\Libraries\Silverlight

If you add an existing behavior from Blend 3.0 a reference to these assemblies is automatically added to your project.

Once you have added the reference it is time to create the class:

   1: public class MouseWheelScrollBehavior : Behavior<Control>
   2: {
   3:     // Add implementation here
   4: }

While we are extending the "scrollable" components in Silverlight we need to create a type that can be attached to Control classes. In silverlight there is not any common class to scrollable components like ScrollViewer, DataGrid and ListBox. This imply we have to find a way to scroll eterogeneous components, but this is matter for the next paragraph. For now simply continue to analyze how to create the Behavior.

The next thing to do is to attach the MouseWheel event on the target object. Once we have extended the Behavior class we have two methods to override useful to handle attach and detach of the behavior to the target: OnAttached is called when the behavior attach an object and OnDetaching when it is detaching from the object. OnAttached and OnDetaching is the perfect location to attach and detach public events that we will handle to give the behavior to the target object. Obviously the target object is exposed by the Behavior<T> in the AssociatedObject property. Here is my code sample:

   1: /// <summary>
   2: /// Called after the behavior is attached to an AssociatedObject.
   3: /// </summary>
   4: /// <remarks>Override this to hook up functionality to the AssociatedObject.</remarks>
   5: protected override void OnAttached()
   6: {
   7:     this.AssociatedObject.MouseWheel += new MouseWheelEventHandler(AssociatedObject_MouseWheel);
   8:     base.OnAttached();
   9: }
  10:  
  11: /// <summary>
  12: /// Called when the behavior is being detached from its AssociatedObject, but before it has actually occurred.
  13: /// </summary>
  14: /// <remarks>Override this to unhook functionality from the AssociatedObject.</remarks>
  15: protected override void OnDetaching()
  16: {
  17:     this.AssociatedObject.MouseWheel -= new MouseWheelEventHandler(AssociatedObject_MouseWheel);
  18:     base.OnDetaching();
  19: }

Now the behavior is ready to be attached to the object but it still does nothing. We need to implement the scrolling for scrollable components, so it is time to enter the next paragraph.

Scrolling the Scrollable... not so simple!

While I'm writing the sample I've attached to this post, there were a moment when I thinked this behavior is impossible to be implemented and I was ready to switch to a less generic ScrollViewer scroller behavior. The reason for this is that there is not any common scrolling interface to scrollable components. So while creating a Behavior for a ScrollViewer is simple, it is not so simple to use it for DataGrid or ListBox.

Just a moment before discarting my sample I've gived a last chance to "bing" to find someone handling the same problem. I finally found this that explain how to use Automation API in Silverlight to enable the scrolling of components without extending them.

I leave the full explanation to the good article I've linked. Here the only thing we need to Know is that Automation API expose a IScrollProvider interface doing exactly what I'm searching for. So we need to change the OnAttached method to create the Automation Peer for the attaching object:

   1: /// <summary>
   2: /// Gets or sets the peer.
   3: /// </summary>
   4: /// <value>The peer.</value>
   5: private AutomationPeer Peer { get; set; }
   6:  
   7: /// <summary>
   8: /// Called after the behavior is attached to an AssociatedObject.
   9: /// </summary>
  10: /// <remarks>Override this to hook up functionality to the AssociatedObject.</remarks>
  11: protected override void OnAttached()
  12: {
  13:     this.Peer = FrameworkElementAutomationPeer.FromElement(this.AssociatedObject);
  14:  
  15:     if (this.Peer == null)
  16:         this.Peer = FrameworkElementAutomationPeer.CreatePeerForElement(this.AssociatedObject);
  17:  
  18:     this.AssociatedObject.MouseWheel += new MouseWheelEventHandler(AssociatedObject_MouseWheel);
  19:     base.OnAttached();
  20: }

First we search the Automation interfaces if the control already created it. If the interface has not been found we need to create it. The AutomationPeer is saved in a member property to be used when the MouseWheel event is raised. Here is the code to scroll the target:

   1: /// <summary>
   2: /// Handles the MouseWheel event of the AssociatedObject control.
   3: /// </summary>
   4: /// <param name="sender">The source of the event.</param>
   5: /// <param name="e">The <see cref="System.Windows.Input.MouseWheelEventArgs"/> instance containing the event data.</param>
   6: void AssociatedObject_MouseWheel(object sender, MouseWheelEventArgs e)
   7: {
   8:     this.AssociatedObject.Focus();
   9:  
  10:     int direction = Math.Sign(e.Delta);
  11:  
  12:     ScrollAmount scrollAmount = 
  13:         (direction < 0) ? ScrollAmount.SmallIncrement : ScrollAmount.SmallDecrement;
  14:  
  15:     if (this.Peer != null)
  16:     {
  17:         IScrollProvider scrollProvider =
  18:             this.Peer.GetPattern(PatternInterface.Scroll) as IScrollProvider;
  19:  
  20:         bool shiftKey = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift;
  21:  
  22:         if (scrollProvider != null && scrollProvider.VerticallyScrollable && !shiftKey)
  23:             scrollProvider.Scroll(ScrollAmount.NoAmount, scrollAmount);
  24:         else if (scrollProvider != null && scrollProvider.VerticallyScrollable && shiftKey)
  25:             scrollProvider.Scroll(scrollAmount, ScrollAmount.NoAmount);
  26:     }
  27: }

When we get the Delta we need to extract the direction of the scrolling. This is because we are unable to speficy the amount of pixels we have to scroll the target but simply the ScrollAmount that may be a SmallIncrement or SmallDecrement (or LargeIncrement, LargeDecrement). So using the direction we decide from Increment and Decrement.

While the controls can scroll both vertically or horizontally I decided to check if the shift key is pressed to allow horizontal scroll. Finally using the Scroll method in the IScrollProvider I apply the scrolling to the target control. This is very simple because the IScrollProvider does all the work for us. There is no need to check boundaries, we have simply to say how to scroll and all the work is done.

Using the Behavior

Using Blend is the simpler way to apply behaviors. The blend assets library scan the classes of the project and show them in the library so dragging the behavior on the scrollable component is sufficient to apply the behavior. We need to learn ho to apply the behavior by code. Here is a sample:

   1: <UserControl
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
   4:     xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
   5:     xmlns:local="clr-namespace:Elite.Silverlight3.MouseWheelSample.Silverlight.Classes"
   6:     xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
   7:     x:Class="Elite.Silverlight3.MouseWheelSample.Silverlight.MainPage" 
   8:     Width="Auto" Height="Auto">
   9:  
  10: ... omissis ...
  11:  
  12: <data:DataGrid Grid.Column="1" Grid.Row="0" ItemsSource="{Binding DataItems}" Margin="20">
  13:     <i:Interaction.Behaviors>
  14:         <local:MouseWheelScrollBehavior />
  15:     </i:Interaction.Behaviors>
  16: </data:DataGrid>

In the UserControl we declare the namespaces we have to use. In this sample "i" stand for interactivity, the assembly where the Behavior<T> classe is located. The "local" refer to the local classes where we put the new Behavior. In the second part we attach the behavior to a DataGrid. To attach the behavior to a ScrollViewer or to a ListBox the code is pretty similar. Running the project we will have the mouse wheel working on the DataGrid.

Conclusion

The tecnique I've illustrated has the big advantage or working for all the scrollable controls but not for ComboBox because it does not directly implements IScrollProvider interface. The drawback is that it works only on windows. This is a big problem but there is not any solution to it while as I already said it is the only way to scroll all the controls programmatically. Moreover we have to take note that the MouseWheel event only works in Windows with Internet Explorer and also with Firefox when you are not using the windowless mode. This is a limitation of the architecture of Safari and Firefox and the only way to work around it is using the DOM events. So due to this limitations the example is a good solution to be used where it works. In the others cases it simply does nothing.

Download: Elite.Silverlight3.MouseWheelSample.zip (1,2 MB)

Video: MouseWheelScrollBehavior.wmv (1.4 MB)

A bit of Physics for an InertialScrollViewer

2009-05-10T01:22:27+01:00 by Andrea Boschin

Silverlight 2.0 and 3.0 come with an useful control called ScrollViewer, that helps when long list of elements needs to be scrolled with a traditional scrollbar. New mobile devices like the iPhone introduced a new kind of ScrollViewer where the user only needs to use his thumb to move the lists of elements on the screen. This beautiful kind of ScrollViewer often give an impressive feedback with a fluid scrolling that ends in a real soft deceleration giving the impression that the bend of elements is subject to the physics rules. This is not only scenic, but give the user a natural feedback that take usability to the maximum levels. So, in this article I would want to illustrate how to apply some simple physics formula to create a reusable InertialScrollViewer to take this feedback into Silverlight applications.

Please note that I'm not a physicist. I have only searched my school notions and tried to get something to work. And it works fine as you will see... :)

How the control has to work

Before entering the coding phase of the control, we need to understand how the control has to work. From the developer perspective the InertialScrollViewer must work similar to the original ScrollViewer. It have to scroll the content generated inside of it and let the user scroll Vertically or Horizontally. My implementation of this control let the developer to choice if scroll Vertically or Horizontally but not in both the directions at the same time.

From the user perspective we have two different phases: when the user click on the band he can move it using the mouse (e.g from left to the right). While the user is moving, the band is simply locked to the mouse and if the user stop scrolling the bend also stops. Only when the user leave the mouse button while he is scrolling, it has to maintain the current speed and decrease it to zero in a variable distance. The calculation of the speed is the most difficult thing, infact we have to take note of the change of direction and not only of the difference from the starting point to the end of the scrolling. If the user start scrolling from left to right and at a given point stops he turn scrolling from the right to left, the speed needs to be recalculated from the direction change and not from the start of the scrolling action. To avoid this kind of problems I decided to sample the speed at every MouseMove event. Every time this event will be raised I take note of "ticks" and "distance" from the previous event and calculate the speed with the simple formula

speed = distance / time

For a better precision I record the last two samples and when the user leave the mouse button I calculate the medium of the two available samples.

The other phase of the user interaction enter when the user stop dragging and the band start decrease its speed. All calculation is done when this event occur. First we have to calculate the distance that the band will race with the starting speed and then we have to calculate how much time it take to decrease speed to zero. The first part use this formula:

distance = speed ^ 2 / 20 * f

This formula, I found in my physics schoolbook, use f as friction factor to determine the type of surface where the bend is moving. A number less then 0.5 determine a slippery surface so the bend will run a long distance. A number from .5 to 1 determine a rough surface. This value is exposed by my control so the developer can change it and give different feedback to the user.

To calculate the time needed for the bend going from the start speed to zero I found another formula that get a deceleration value. Here is the formula

time = -speed / -a 

Where "-a" is the negative acceleration. This formula result from a more complicated formula that I've simplified due to some 0 occurrence. The simplification process is out of the scope of this article.

Now that we have all calculation done, it is time to start implementing the control.

The InertialScrollViewer ControlTemplate

The first thing to do is implementing a templated control. Like every control in Silverlight the InertialScrollViewer will take advantage of a template that will be saved in Themes/generic.xaml. Here we cannot inherit from the ScrollViewer control because it is sealed so our custom scroller will be a ContentControl and it allow to scroll content put into itself.

The template or the InertialScrollViewer is made of a Border containing a Canvas and then a ContentControl. I put some defaults to give the InertialScrollViewer an appearance similato to the original ScrollViewer. Here is the template:

   1: <Style TargetType="local:InertialScrollViewer">
   2:         <Setter Property="Padding" Value="0"/>
   3:         <Setter Property="Background" Value="#FFFFFFFF"/>
   4:         <Setter Property="BorderThickness" Value="1"/>
   5:         <Setter Property="VerticalContentAlignment" Value="Stretch"/>
   6:         <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
   7:         <Setter Property="BorderBrush">
   8:             <Setter.Value>
   9:                 <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
  10:                     <GradientStop Color="#FFA3AEB9" Offset="0"/>
  11:                     <GradientStop Color="#FF8399A9" Offset="0.375"/>
  12:                     <GradientStop Color="#FF718597" Offset="0.375"/>
  13:                     <GradientStop Color="#FF617584" Offset="1"/>
  14:                 </LinearGradientBrush>
  15:             </Setter.Value>
  16:         </Setter>
  17:         <Setter Property="Template">
  18:             <Setter.Value>
  19:                 <ControlTemplate>
  20:                     <Border x:Name="RootElement" 
  21:                             CornerRadius="2"                            
  22:                             Padding="{TemplateBinding Padding}"
  23:                             Background="{TemplateBinding Background}"
  24:                             BorderBrush="{TemplateBinding BorderBrush}" 
  25:                             BorderThickness="{TemplateBinding BorderThickness}">
  26:                         <Border.Resources>
  27:                             <Storyboard x:Name="EasingStoryboard">
  28:                                 <DoubleAnimation />
  29:                             </Storyboard>
  30:                         </Border.Resources>
  31:                         <Canvas x:Name="CanvasElement">
  32:                             <ContentControl x:Name="ContentElement"
  33:                                             Content="{TemplateBinding Content}"
  34:                                             VerticalAlignment="Stretch"
  35:                                             HorizontalAlignment="Stretch"
  36:                                             VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
  37:                                             HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" />
  38:                         </Canvas>
  39:                     </Border>
  40:                 </ControlTemplate>
  41:             </Setter.Value>
  42:         </Setter>
  43:     </Style>

The <Border /> "RootElement" inside the template will be the outer border of the control. It receive the default values and have a shaded BorderBrush. It contains a StoryBoard into its resources. I will return on it later in the article.

The <Canvas /> "CanvasElement" is required to be able to scroll the ContentControl I put inside of it. After doing some tests I found that the Canvas is the only control that let me apply some Transform to the ContentControl and continue to show the content without any clipping. People using the control will have no knowledge about the Canvas.

Finally the ContentControl has been configured to let the content stretch to fill all the available space. Its VerticalContentAlignment and HorizontalContentAlignment property has been binded to the corresponding template properties so the user can configure the control behavior.

Let's do some code...

Now it is time to start coding. The control is about 300 line long so it is impossible to explain all the code. I will explain the key point following the control lifetime. After doing some inizialization in the control constructor the first place where it is required we write some code is the OnApplyTemplate method. Inside this method we have to hook every element of our template. The elements will be assigned to some member properties using the GetTemplateChild method. To let the control customizable I have also specified the TemplatePart attributes on top of the class. Here is the parts:

   1: [TemplatePart(Name = InertialScrollViewer.RootElementName, Type = typeof(Border))]
   2: [TemplatePart(Name = InertialScrollViewer.CanvasElementName, Type = typeof(Canvas))]
   3: [TemplatePart(Name = InertialScrollViewer.ContentElementName, Type = typeof(ContentControl))]
   4: [TemplatePart(Name = InertialScrollViewer.EasingStoryboardName, Type = typeof(Storyboard))]

Every element has its own wrapping constant to centralize the names in a single point. During the OnApplyTemplate this names will be used to pick up the elements and assign to the corresponding properties. I also create a TranslateTransform into this method and assign it to the RenderTransform property of the ContentControl. The reason to create the TranslateTransform - used to scroll the content - is that if the user customize it can easily break the control functionality.

   1: public override void OnApplyTemplate()
   2: {
   3:     // Border
   4:     this.RootElement = GetTemplateChild(InertialScrollViewer.RootElementName) as Border;
   5:  
   6:     // Canvas
   7:     this.CanvasElement = GetTemplateChild(InertialScrollViewer.CanvasElementName) as Canvas;
   8:     this.CanvasElement.SizeChanged += new SizeChangedEventHandler(CanvasElement_SizeChanged);
   9:  
  10:     // clip the content to the Width and Height
  11:     this.CanvasElement.Clip =
  12:         this.CanvasClipping = new RectangleGeometry
  13:         {
  14:             Rect = new Rect(0, 0, this.CanvasElement.ActualWidth, this.CanvasElement.ActualHeight)
  15:         };
  16:  
  17:     // ContentControl
  18:     this.ContentElement = GetTemplateChild(InertialScrollViewer.ContentElementName) as ContentControl;
  19:     this.ContentElement.RenderTransform =
  20:         this.Translate = new TranslateTransform { X = 0, Y = 0 };
  21:  
  22:     this.ContentElement.MouseLeftButtonDown += (a, b) => this.HandleMouseDown(this.GetMousePosition(b, this.Orientation));
  23:     this.ContentElement.MouseLeftButtonUp += (a, b) => this.HandleMouseUp(this.GetMousePosition(b, this.Orientation));
  24:     this.ContentElement.MouseMove += (a, b) => this.HandleMouseMove(this.GetMousePosition(b, this.Orientation));
  25:  
  26:     // StoryBoard
  27:     this.EasingStoryboard = this.RootElement.Resources[InertialScrollViewer.EasingStoryboardName] as Storyboard;
  28:     this.EasingAnimation = this.EasingStoryboard.Children.OfType<DoubleAnimation>().FirstOrDefault();
  29:  
  30:     // let do some inizialization
  31:     this.OnOrientationChanged(this.Orientation);
  32:     this.OnEasingFunctionChanged(this.EasingFunction);
  33:  
  34:     // and call the base class
  35:     base.OnApplyTemplate();
  36: }

The last thing to take note is the Clipping. The Canvas is a control that do not have a frame. The content can be put at negative coordinates but it is not clipped if there is some space available. So I have created a RectangleGeometry and I use it to clip the Canvas at his ActualWidth and ActualHeight. This is done in the CanvasElement_SizeChanged event handler every time the size of the element will be changed.

During the OnApplyTemplate method I attach some event handlers to the ContentControl to handle the Mouse events MouseMove, MouseLeftButtonDown and MouseLeftButtonUp. This events let me know when the user try to scroll the content.

In the MouseLeftButtonDown I do some inizialization. I Capture the mouse, inizializa the Translation and then start the sampling using an instance of the SpeedSample class. In the MouseMove I do the sampling using the same specialized class SpeedSampler. The SpeedSampler class is responsible to count the incoming events from MouseMove and record the last two samples. In my opinon the class is pretty simple and do not need any explanation. In the same event I also apply the value to the TranslateTransform to move the content to the required position.

When the user leave the mouse button the flow goes to the MouseLeftButtonUp event handler and inside of it I do alle the required calculation. First of all I take note of the current speed and then I calculate the distance and the duration of the deceleration.

   1: /// <summary>
   2: /// Handles the mouse up.
   3: /// </summary>
   4: /// <param name="mousePosition">The mouse position.</param>
   5: private void HandleMouseUp(double mousePosition)
   6: {
   7:     if (this.GetBoundary(this.Orientation) >= 0) return;
   8:  
   9:     this.IsCaptured = false;
  10:     this.ContentElement.ReleaseMouseCapture();
  11:     double speed = this.Sampler.GetSpeed();
  12:  
  13:     if (this.EasingStoryboard != null && this.EasingAnimation != null)
  14:     {
  15:         this.EasingAnimation.To = this.ComputeNextPosition(Math.Pow(speed, 2) / (20 * this.FrictionFactor) / 1000 * this.Sampler.Direction);
  16:         this.EasingAnimation.Duration = TimeSpan.FromSeconds(-(speed / 1000) / -this.Deceleration);
  17:         this.EasingStoryboard.Begin();
  18:     }
  19: }

Once I have calculated this parameters the only thing I have to do is to assign them to the Storyboard and start the animation. The EasingStoryboard has been picked up from the template and will run the scroller to its calculated end position. If the user will click on the content during the easing animation I simply stop the animation and forget all the calculation.

The Storyboard has a default QuadraticEasing function applied that to me is the better choice to give a natural behavior. The control expose an EasingFunction property to let the user cutomize the animation easing. Putting and ElasticEase give the control an astounding elastic behavior.

The control expose some other properties to let the user customize it. Orientation let you decide if scrolling is vertical or horizontal. FrictionFactor and Deceleration let customize the physics parameters. I suggest you to try by yourself changing the properties and the easing to give the control the preferred behavior.

Some final words.

Attached to this article you will find the complete source of the control. I would like to have your feedback about how it works. I made many tests and to me it is working fine but I'm sure that it is not perfect. If you find some strange behavior please post a comment and I will try to get rid of it.

Download: (~1.1 MB)

Video: (~2.6 MB)

Silverlight 3.0: Out of browser experience

2009-03-18T19:00:00+01:00 by Andrea Boschin

Read also updates targeting Silverlight 3.0 RTW
http://www.silverlightplayground.org/post/2009/07/10/Whats-new-about-Out-Of-Browser-in-Silverlight-30-RTW.aspx 

Many times, when using a Silverlight application, I thinked about how cool would be to detach the application from the browser and use it directly from my desktop. Some Silverlight application are really lightweighted and can easily used on many platforms without to have to install it in the computer; the only thing needed is the Silverlight runtime.

This scenario I've described in a few words may open the way to a new big set of applications. Think as an example at an application that may be used both online and offline checking for network connectivity and synchronizing the modification of the local storage to a global online repository. You may detach multiple instances of the application in many computers, the office workstation, the home PC, your mini notebook and have them synchronized each other when you apply some changes. This may be a real occasionally connected application.

Out of browser experience and Silverlight 3.0

ctxmenu The biggest feature of the new Silverlight 3.0, called Out of browser experience, OOB for the friends, let you start creating application that can easily detached and used from a simple host without the need of a browser instance. The action of detaching the application is really simple, very fast and do not need any kind of installer. You have simply to right click the running application and if it is configured correctly you will find an "Install ... onto this computer..." item. The only question you need to answer is where you want silverlight let create the icon, on the Desktop or in the Start menu (or both) and then your OOB will be started and ready to be used.

The use of this kind of experience need open some problem we will analize in the next paragraphs, as usual using a small project as a guide. I've build a very tiny ToDoList application in Silverlight to let manage some simple todo, with a title a description and an optional due date. The application is ready to detect network changes and to synchronize contents using a WCF service, but this part is not implemented because is out of the scope of this article.

Configuring the Out Of Browser Experience

The first problem we have to address after we have completed our development, is how to configure it to let the user detach the application to be able to run it online and offline without a browser. This is a quite simply task. In the silverlight project you have to find the AppManifest.xml file under the Properties folder and uncomment a special section. Obviously you may also customize some properties:

   1: <Deployment.ApplicationIdentity>
   2:   <ApplicationIdentity ShortName="ToDoList"
   3:                        Title="Silverlight ToDoList">
   4:     <ApplicationIdentity.Blurb>
   5:       Manage offline your tasks
   6:     </ApplicationIdentity.Blurb>
   7:   </ApplicationIdentity>
   8: </Deployment.ApplicationIdentity>

The properties you can customize are the ShortName that will appear on the menu item, the title and the description (blurb) that will be displayed in the installation window. You may also add an optional <ApplicationIdentity.Icons> section. This let you add some icons in png format to be displayed on the desktop or start menu.

install

The installation window let you decide how to install  the application you are detaching. You may choice to add some icons, one on the destop and one on the Start menu.

This is the only action you need to perform. If you click yes the files required to run the application will be copied into a folder in AppData and the icons wil be created as shortcut to the sllauncher.exe into the Silverlight 3.0 install location.

The folder where the application files will be copied is C:\User\...\AppData\LocalLow\Microsoft\Silverlight\Offline.

After installing the OOB application you may run it again double clicking on the icons. You may also uninstall it simply right clicking on the running instance and selecting "Remove this application..." from the context menu.

The installation process may be triggered programmatically using the Detach() method of the Application class. This the the developer to add a button that indicate to the user that the application may be detached. The Application.RunningOffline property let the developer know if the Application is already detached. Using this property we may show the installation instructions when the application is in the browser and the remote them when installed.

If you imagine to have a "detach" button you can write this code:

   1: this.detach.Visibility = 
   2:     Application.Current.RunningOffline ? Visibility.Collapsed : Visibility.Visible;
   3:  
   4: this.detach.Click += (sender, e) => Application.Current.Detach();

We may get information about the installation (detaching) or disinstallation of the application handling the event ExecutionStateChanged and reading the ExecutionState property in the Application.Current instance. This property let us know that the state of the application is:

  • Detached - The application has successful detached
  • DetachedUpdatesAvailable - see the paragraph (Updating the application)
  • DetachFailed - The detach is failed
  • Detaching - The detach is in progress
  • RunningOnline - The application is into the browser

Store local data: Isolated Storage

Running an Out of browser application imply to have a location where to store some data when the application is Offline. Unfortunately there is no way to access the local filesystem, also if the application is Detached by the user and also there is not any way to consume some kind of database (e.g. a Sql Server Mobile file).

The only place you can use to persist information is the local IsolatedStorage. The example application attached to this article use the IsolatedStorage to persist a simple XML file containing the Tasks and the actions the user apply to them. This XML is loaded at the application startup and saved to the storage every time the user modify the data. To handle the synchronization of the modification to the online store the XML contains a status and version for each Task. This information may be used by the WCF Service to manage the updating of the online store.

Detecting network changes

After our OOB application is ready and works against the isolated storage we needs to detect when the user go online to trigger the syncronization with the online storage. The sncronization is made of two parts: we need to update the online store with the updates applied locally and the we needs to download locally the updates applied by other instances of the OOB application.

Detecting the network changes is sligthly simple. We may use two classes called NetworkChange and NetworkInterface. The first class expose and event that let us known when the network status has changed from online to offline and viceversa:

   1: NetworkChange.NetworkAddressChanged +=
   2:     new NetworkAddressChangedEventHandler(NetworkChange_NetworkAddressChanged);
   3:  
   4: // ... omissis ...
   5:  
   6: private void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
   7: {    
   8:     if (NetworkInterface.GetIsNetworkAvailable() && this.NeedUpdate)
   9:     {
  10:  
  11:     }
  12: }

The events triggered by the NetworkChange class do not contains any informations about the connection is up or down. This event let us to know only that something has changed. Also we have to take note that the event will be triggered multiple times depending how many adapters are connected to the host computer so we have to handle this event accurately.

To detect if we are are running online or offline we may use the GetIsNetworkAvailable() method. This method returns true if this ia any connected network else it returns false. In the application we check also the NeedUpdate property to avoid that the update process will be triggered too many times if the network connect or disconnect many times due to network instability. In this application NeedUpdate returns true only if at least 1 hour has passed after the last successful update.

Updating the application

When an application is running online every time we connect to the host site we get the latest version of the application. The silverlight plugin handles the updates of the xap downloading the file and discarting the cached version. When an application has ben taken out of browser we needs to have this check to run sometimes because we want our applicatio remain up to date.

The Silverlight 3.0 OOB application run this check every time the application starts on the host computer. If the network is available and an update has been detected the new xap will be downloaded and then the running application will be notified of the available update. It is in charge of the developer to decide to show to the user that the application has been updated. However when the application is closed and restarted the update will be applied. Here is the code to get the notification about updates:

   1: Application.Current.ExecutionStateChanged += 
   2:     new EventHandler(Current_ExecutionStateChanged);
   3:  
   4: // ... omissis ...
   5:  
   6: void Current_ExecutionStateChanged(object sender, EventArgs e)
   7: {
   8:     if (Application.Current.ExecutionState == ExecutionStates.DetachedUpdatesAvailable)
   9:         MessageBox.Show("Updates have been downloaded. Please restart the application to apply this updates.");
  10: }

There is no way to break the update process. When the application detect an update it try to download the new application and updates itself. I something fail (e.g. the network is disconnected), the update process restarts the next time the application run.

Running the sample

Attached to this article you may found a Visual Studio 2008 project that shows a real application using the Out Of Browser Experience. To run this sample you need to have the Silverlight 3.0 installed and the Silverlight Tools for Visual Studio 2008 updated to the latest version. You have to know that after installing this updates the computer will be a full Silverlight 3.0 machine so if you have to develope something with Silverlight 2.0 it is better you not install anything.

I think the OOB experience will trigger many new applications. The simple ToDoList I've created is the evidence that unleashing your fantasy you may think about many applications of this tecnique. In the next month I hope many of you will stars publish your own sample.

Download code: (2.02 MB)

Demo Video: (3.5 MB)

Creating a MouseClickManager to handle single and double mouse clicks

2009-03-17T00:06:00+01:00 by Andrea Boschin

One of the missing things of Silverlight is the capability to handle mouse double click events. This problem apply not only to Silverlight 1.0 but also to Silverlight 2.0 Beta 1 and 2. Silverlight is rich about Mouse event handling but have two limitations. The first one is the missing right-mouse-button handling due to the presence of a contextual menu for configuration of the plugin. The second thing is the presence of mouse up and down left-button events but not of the click and double-click.

So, I decided to create a small class to handle this problem in a simply way. The class I created behave as a translator that receive mouse-up events and transform them in click/double-click. The only way to discriminate from single to double click is taking care of a brief timeout (300 ms) after the first incoming mouse-up event. If this timeout expires without another incoming mouse-up event we have to raise a click event. Instead, if a second mouse-up arrive we need to raise a double-click event.

Handling events in this way has a little bit problem. We need to receive an event and then wait for another event without blocking the caller and the user interface itself. With javascript I handled this problem using a setTimeout() that reset a flag and raise the correct event after the timeout. With Silverlight 2.0 we need to use a Thread because it is the only way to wait an event without blocking the main thread.

My MouseClickManager class handle the problem in this way. In the next code block I show the main methods of the class:

   1: /// <summary>
   2: /// Handles the click.
   3: /// </summary>
   4: /// <param name="sender">The sender.</param>
   5: /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
   6: public void HandleClick(object sender, MouseButtonEventArgs e)
   7: {
   8:     lock(this)
   9:     {
  10:         if (this.Clicked)
  11:         {
  12:             this.Clicked = false;
  13:             OnDoubleClick(sender, e);
  14:         }
  15:         else
  16:         {
  17:             this.Clicked = true;
  18:             ParameterizedThreadStart threadStart = new ParameterizedThreadStart(ResetThread);
  19:             Thread thread = new Thread(threadStart);
  20:             thread.Start(e);
  21:         }
  22:     }
  23: }
  24:  
  25: /// <summary>
  26: /// Resets the clicked flag after timeout.
  27: /// </summary>
  28: /// <param name="state">The state.</param>
  29: private void ResetThread(object state)
  30: {
  31:     Thread.Sleep(this.Timeout);
  32:  
  33:     lock (this)
  34:     {
  35:         if (this.Clicked)
  36:         {
  37:             this.Clicked = false;
  38:             OnClick(this, (MouseButtonEventArgs)state);
  39:         }
  40:     }
  41: }

In the HandleClick method we receive the incoming events. Probably the event handler of the MouseLeftButtonUp event simply call this method passing sender and arguments. In this method first of all we need to acquire a lock on a shared resource. This resource is the "clicked" flag that indicate if we are handling the first or second event. After acquiring the lock we have two choices. If the clicked flag is set to false we are handling the first click event so we need to set the flag and start a thread that will wait 300 milliseconds before reset the flag. So if the clicked flag has not been reset when we receive the second mouse-up then we are handling a double click event. 

This may appear simply, but it has a little drawback. When we need to raise the single-click event, we are running in a separate thread so we may incur in a cross thread situation and we need to marshal the thread context to the main thread itself to avoid this condition. This is a common problem in windows forms environment and also in WPF. To handle the problem we have to use the Dispatcher object. In this code snippet I show a brief example:

   1: /// <summary>
   2: /// Called when click occure.
   3: /// </summary>
   4: /// <param name="sender">The sender.</param>
   5: /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
   6: private void OnClick(object sender, MouseButtonEventArgs e)
   7: {
   8:     MouseButtonEventHandler handler = Click;
   9:  
  10:     if (handler != null)
  11:         this.Control.Dispatcher.BeginInvoke(handler, sender, e);
  12: }

"Control" is a reference to the control that we have to notify the event. So we will user the Control.Dispatcher.BeginInvoke() method to marshal the event. To use my class MouseClickManager you have simply to crate an instance passing a reference to the control that will receive the click/double click events. Than in the MouseLeftButtonUp event you will call the HandleClick method. The event handler connected to Click and DoubleClick events will be called appropriately.

The class has been designed to configure the the timeout lenght. Some experiments revealed that 200 ms is less, but 400 ms is too much because we will begin to feel the click event delay.

Download: http://www.codeplex.com/SilverlightLibrary