XAML Playground
about XAML and other Amenities

Silverlight 5.0: Custom Markup Extensions and Roles

2011-04-23T00:54:32+01:00 by codeblock

Starting from Silverlight 5.0 you can create custom Markup Extensions and this is an interesting feature to easily encapsulate some logic and make it easy to be applied to properties in the XAML markup. Until now you could only use a few extensions to apply resources (StaticResource), make databinding (Binding) and connect properties with parts of a template (TemplateBinding) but now, implementing a really simple interface you can build your own.

   1: public interface IMarkupExtension<out T> where T: class
   2: {
   3:     T ProvideValue(IServiceProvider serviceProvider);
   4: }

Using this interface you can specify the type to which the markup extension can be applied (the generic type T) but if you do not need a control about this type you can extend the MarkupExtension abstract class that is like you are extending IMarkupExtension<object>.

Inside the ProvideValue method there is the whole logic of the extension and using the IServiceProvider passed by the runtime you can get access to three services that let you get some informations about the markup where the extension is located.

IRootObjectProvider: provide a reference to the Root object of the VisualTree which the element is part of

IXamlTypeResolver : is able to resolve the name of the tags in the markup to the corresponding type.

IProvideValueTarget : gets a reference to the property and the elements which the markup extension is assigned

To retrieve an instance of this services you can use the GetService method on the IServiceProvider instance.

IProvideValueTarget target = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));

In this example I wrote a RoleBinding extension that a developer can use to connect parts of the User Interface with a Validator class that is able to authorize the access to these parts using a set of custom rules. Let start writing the markup extension:

   1: using System;
   2: using System.Net;
   3: using System.Windows;
   4: using System.Windows.Controls;
   5: using System.Windows.Documents;
   6: using System.Windows.Ink;
   7: using System.Windows.Input;
   8: using System.Windows.Media;
   9: using System.Windows.Media.Animation;
  10: using System.Windows.Shapes;
  11: using System.Windows.Markup;
  12: using System.Security.Principal;
  13: using System.Windows.Data;
  14: using System.Xaml;
  15: using System.ComponentModel;
  16: using System.Diagnostics;
  17: using System.Security;
  18: using System.Reflection;
  19: using System.Globalization;
  20:  
  21: namespace SLPG.MarkupExtensions
  22: {
  23:     public class RoleBindingExtension : MarkupExtension
  24:     {
  25:         /// <summary>
  26:         /// Gets or sets the name of the group.
  27:         /// </summary>
  28:         /// <value>
  29:         /// The name of the group.
  30:         /// </value>
  31:         public string GroupName { get; set; }
  32:         /// <summary>
  33:         /// Gets or sets the name of the feature.
  34:         /// </summary>
  35:         /// <value>
  36:         /// The name of the feature.
  37:         /// </value>
  38:         public string FeatureName { get; set; }
  39:         /// <summary>
  40:         /// Gets or sets the converter.
  41:         /// </summary>
  42:         /// <value>
  43:         /// The converter.
  44:         /// </value>
  45:         public IValueConverter Converter { get; set; }
  46:         /// <summary>
  47:         /// Gets or sets the converter parameter.
  48:         /// </summary>
  49:         /// <value>
  50:         /// The converter parameter.
  51:         /// </value>
  52:         public object ConverterParameter { get; set; }
  53:  
  54:         /// <summary>
  55:         /// Provides the value.
  56:         /// </summary>
  57:         /// <param name="serviceProvider">The service provider.</param>
  58:         /// <returns></returns>
  59:         public override object ProvideValue(IServiceProvider serviceProvider)
  60:         {
  61:             IProvideValueTarget target = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
  62:  
  63:             bool isAuthorized = false;
  64:  
  65:             if (RoleManager.Current != null)
  66:                 isAuthorized = RoleManager.Current.Validator.Authorize(this.GroupName, this.FeatureName);
  67:             else
  68:                 isAuthorized = true;
  69:  
  70:             if (this.Converter != null)
  71:                 return this.MapToType(isAuthorized, target, this.Converter, this.ConverterParameter);
  72:  
  73:             return this.MapToType(isAuthorized, target);
  74:         }
  75:  
  76:         /// <summary>
  77:         /// Maps to type.
  78:         /// </summary>
  79:         /// <param name="isAuthorized">if set to <c>true</c> [is authorized].</param>
  80:         /// <param name="target">The target.</param>
  81:         /// <param name="converter">The converter.</param>
  82:         /// <param name="converterParameter">The converter parameter.</param>
  83:         /// <returns></returns>
  84:         private object MapToType(bool isAuthorized, IProvideValueTarget target, IValueConverter converter, object converterParameter)
  85:         {
  86:             PropertyInfo info = target.TargetProperty as PropertyInfo;
  87:  
  88:             if (info != null)
  89:                 return converter.Convert(isAuthorized, info.PropertyType, converterParameter, CultureInfo.CurrentCulture);
  90:  
  91:             return isAuthorized;
  92:         }
  93:  
  94:         /// <summary>
  95:         /// Maps to type.
  96:         /// </summary>
  97:         /// <param name="isAuthorized">if set to <c>true</c> [is authorized].</param>
  98:         /// <param name="target">The target.</param>
  99:         /// <returns></returns>
 100:         private object MapToType(bool isAuthorized, IProvideValueTarget target)
 101:         {
 102:             PropertyInfo info = target.TargetProperty as PropertyInfo;
 103:  
 104:             if (info != null)
 105:             {
 106:                 if (info.PropertyType == typeof(Visibility))
 107:                     return isAuthorized ? Visibility.Visible : Visibility.Collapsed;
 108:             }
 109:  
 110:             return isAuthorized;
 111:         }
 112:     }
 113: }

First of all I extend the MarkupExtension class. The core of the extension is the ProvideValue method. Inside this method I get a service that implements the IProvideValueTarget interface to retrieve informations about the property where the extension is applied to. In my case I need to know the type of the property because I have to map the boolean information (true means authorized, false means not authorized) to the property. For example if the target property is Visibility I map the true to Visible and false to Collapsed.

A markup extension can have a number of parameters. They are public properties exposed by the class. Differently from other existing extensions the custom extensions cannot have unnamed parameters. This is a choice of the Silverlight team I hope will change in future releases just to make extensions very close to the WPF ones. In my case the extension support these parameters:

GroupName and FeatureName: two strings that are used to select the feature and the category of feature the element is part. You can specify for example "Products" as GroupName and "Create" as feature. The values and their meaning are completely up to you. By default they are interpreted as role names where the two parts are joined by a dot: GroupName.FeatureName.

Converter and ConverterParameter: like the Binding extension it is a class that implements IValueConverter and a parameter passed to the class during the conversion. It is used to apply custom conversion to the boolean value that comes from the Validator. In the code provided with the post I use a converter to map the boolean to a Color (Red or Green). 

The extension rely on a Lifetime Object that contains the roles granted to the current user. In my example these roles are passed using the InitParams but please do not repeat this in a production environment because a malicious user can easily impersonate different roles. Probably the better thing  is to use an AuthorizationDomainService provided by the WCF RIA Services.

Once you add the RoleManager service to the App.xaml you can also specify a custom validator that will get the authorization requests and can apply every type of logic you need to perform the authorization. This class can be easily created by implementing the IRoleManagerValidator interface.

You can download the code of this article using the following link. I appreciate every suggestion to improve this extension.

Download: SLPG.MarkupExtensions.zip (30KB)

Categories:   News
Actions:   E-mail | del.icio.us | Permalink | Comments (0) | Comment RSSRSS comment feed

Silverlight 5.0: Plotting beautiful 3D functions

2011-04-13T19:24:00+01:00 by codeblock

1Following the announcement made today on the scene on MIX 2011 I’ve prepared an example for the purpose of showing the new powerful 3D available in the beta bits. Remembering ancient days when I enjoyed myself writing small programs to plot 3D functions on the screen of my Amiga 500, I decided to follow again this path and put together a few lines of code to draw the sample functions in Silverlight (so this pairs with the fractals experiments made in occasion of MIX 2009).

Drawing 3D scenes in Silverlight is not so intuitive as it is in WPF due the fact that the API exposed by the plugin is on a lower level than the WPF one. The team choosed to implement an API that is very close to the XNA framework one. So to create objects in 3D space you have to deal with lot of triangles, vertex and pixel shaders and other exotic stuff. Nonetheless, once you understand the way the thing works the results don’t delude you.

Basically to create a 3D scene you have to put in the markup a special element named DrawingSurface. This element is able to render a 3D set. Every time it surface needs to be rendered it raises an OnDraw event passing to the handler and instance of a GraphicsDevice that is useful to actually draw the scene on the surface. In the example a class named Scene is used to setup the 3D environment (camera, viewing direction and elements in the scene) do inside the OnDraw event the Scene’s Draw method is called to perform the draw.

2Inside the Scene class every element draw itself. In my case the scene is populated only by FunctionPlot class that contains the function to draw and receives some parameters. During the rendering is is possible to apply some transformation matrices that apply rotation, translation and scaling.

The drawing of the function is probably the simplest thing. While the x and y coordinates run on the plane the vertexs of a square are build. The area of every square is divided in two triangles.

A detailed explanation of how the 3D pipeline works is out of the scope of this article and should take an huge number of posts, not few lines. For now I give you the code I wrote for this example and I hope you appreciate like me the beautiful images that it creates.

Download: SLPG.3D.zip (256kb)

Categories:  
Actions:   E-mail | del.icio.us | Permalink | Comments (0) | Comment RSSRSS comment feed

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

TrailWithcount and TrailWithTime: the regular way but with performance impact

2011-04-01T14:19:47+01:00 by Andrea Boschin

Today @saldoukhov pointed me to an alternative (and possibly regular) way to implement TrailWithCount, different from the version I introduced yesterday in my latest post. This tecnique invole the use of a bunch of methods from the Reactive Extensions and, at first sight may result more simple and straightforward. Also if @saldoukhov pointed to the sole count version it is also possibile to write a TrailWithTime this way. Here is the new implementation of these methods:

   1: // BE AWARE THAT THESE METHODS HAVE HUGE PERFORMANCE IMPACT
   2:  
   3: public static IObservable<IEnumerable<T>> TrailWithCount<T>(this IObservable<T> observable, int count)
   4: {
   5:     return observable.Scan(
   6:         Enumerable.Empty<T>(),
   7:         (a, b) => a.StartWith(b).Take(count));
   8: }
   9:  
  10: public static IObservable<IEnumerable<T>> TrailWithTime<T>(this IObservable<T> observable, TimeSpan timeSpan)
  11: {
  12:     return observable
  13:         .Select(o => new Timestamped<T>(o, DateTime.Now))
  14:         .Scan(
  15:             Enumerable.Empty<Timestamped<T>>(), (a, b) =>
  16:                 a.StartWith(b).TakeWhile(o => (DateTime.Now - o.Timestamp).TotalMilliseconds <= timeSpan.TotalMilliseconds))
  17:         .Select(k => k.Select(o3 => o3.Value));
  18: }

Both the methods work the same way with the sole difference that the TrailWithTime wraps the Point in a Timestamped instance and then unwraps it just before returning to the caller. Here the Scan method is an aggregation function that forward every occurrence from the stream and populate a resulting aggregation. So the StartWith method let the aggregation grow and then the Take method extract the "counted" instances we really need.

The problem here is that if you try to run this method on a very large number of items (e.g. 1000) you will see a huge performance impact that leave the start of the trail far from the mouse pointer. The effect is so far more evident if you try to use the TrailWithTime with a long timeout (e.g. 5/10 sec).

As far as I understood these methods have an huge payload in terms of iterations and of garbage they produce. Every time you get an event on the stream a new instance of the array is created and it is crawled to create the result. The TrailWithTime has the worst performances because it produces a great number of Timestamped<> instances. I'm not aware of the inner working of the Scan, StartWith and Take methods but the resulting effect is really clear

If you try to run my previous version with a similar interval you will see a very tiny performance impact. Internally I use a queue and the sole payload are the collection of the Dequeued items (but they would have been collected the same if there is not the trail) and the iteration along the resulting collection to create a PointCollection. This is an interesting demonstration of how the use of LINQ may affect drammatically the performances of an application and I suggest you to double check when you use them.

By the way, thanks to @saldoukhov for his suggestion that I had not considered when I wrote for the first time my Trail methods.

Writing TrailWithCount and TrailWithTime methods with Reactive Extensions (and incidentally drawing a mouse trail)

2011-04-01T00:05:38+01:00 by codeblock

I have to confess, the more I play with reactive extensions the more I enjoy the result I get and appreciate their power. With this post I would like to show how it is possible to  take advantage of these extensions to easily obtain something that normally requires a complex code. The example is really simple and probably not so useful by itself but there are lot of uses I can imagine for the trail functions I will show in a few.

Using the Reactive Extensions make very simple to collect and manipulate the events coming from a source, like you are querying a database. The library itself define a number of methods that operate this way. The buffering functions for instance take a stream of events and collect them in groups based on count or timeout. BufferWithCount gives chunks of counted events and BufferWithTime collect the events generated in a specific timeout.  For example, given this sequence:

1,2,3,4,5,6,7,8,9

TrailWithCount(3) returns

1,2,3 - 4,5,6 - 7,8,9

In the following code I show an extension method that is able to collect the events creating a Trail based on count. I called it TrailWithCount; Given the previous collection the result will be

1,2,3 - 2,3,4 - 3,4,5 - 4,5,6 - etc...

   1: public static IObservable<IEnumerable<T>> TrailWithCount<T>(this IObservable<T> observable, int count)
   2: {
   3:     Queue<T> queue = new Queue<T>();
   4:  
   5:     return observable.Select(
   6:         o =>
   7:         {
   8:             queue.Enqueue(o);
   9:  
  10:             while (queue.Count > count) queue.Dequeue();
  11:             return queue.ToArray();
  12:         });
  13: }

This method take in input an IObservable<T> and returns an IObservable<IEnumerable<T>>. This is very close to the BufferWithCount method that returns an IObservable<IList<T>>. I preferred the use of IEnumerable<T> instead of IList<T> because I do not need the Insert and Remove methods of this interface. In the first row of the method I create a Queue<T>. It is important to remember that this collection will be created once the first time the method is called and thanks to the usage of lambda expression it will be alive and available to the body of the Select method for each event we get from the stream.

So, every time we get an event, in the Select method I add it to the Queue and then I remove the ones that exceed the count. Finally I select the items in the queue a result of the lambda expression so they are forwarded to the next extension method in the chain.

The same way, but taking advantage od the Timestamped<T> class I can operate to collect the trail events by time. The Timestamped<T> class is useful to add a timestamp (the moment when the event was received) to the item I add to the queue. So instead of removing items from the queue when they exceed a count I compare the timestamp with the current time and I remove the ones that are outside the defined timeout. Here is the method:

   1: public static IObservable<IEnumerable<T>> TrailWithTime<T>(this IObservable<T> observable, TimeSpan timeSpan)
   2: {
   3:     Queue<Timestamped<T>> queue = new Queue<Timestamped<T>>();
   4:  
   5:     return observable.Select(
   6:         o =>
   7:         {
   8:             DateTime now = DateTime.Now;
   9:  
  10:             queue.Enqueue(new Timestamped<T>(o, now));
  11:  
  12:             while (now - queue.Peek().Timestamp > timeSpan)
  13:                 queue.Dequeue();
  14:  
  15:             return queue.Select(v => v.Value).ToArray();
  16:         });
  17: }

Ok, now that we got the Trail method it is time to use them. To visualize the resulting trail I will catch the MouseMove events and collect the resulting points to draw the trail on the plugin area. So first of all I attach the MouseMove using the Observable.FromEvent then I transform the output events to a stream of Point calling GetPosition for every EventArgs. Finally I call the TrailWithCount (or TrailWithTime) method just before subscribing to the stream.

   1: Observable.FromEvent<MouseEventHandler, MouseEventArgs>(
   2:     ev => new MouseEventHandler(ev),
   3:     ev => this.LayoutRoot.MouseMove += ev,
   4:     ev => this.LayoutRoot.MouseMove -= ev)
   5:     .Select(o => o.EventArgs.GetPosition(this.LayoutRoot))
   6:     .TrailWithTime(TimeSpan.FromSeconds(3))
   7:     .Subscribe(DrawLine);

The Subscribe method will call a Draw method that simply assign the points of the trail to a Polyline. This will show a trail that grow to the required length then is shortened at the end when the mouse moves. Here you can try by yourself moving the mouse on the following instance of the plugin:

Get Microsoft Silverlight

In the attached code you can download you will find the methods I discussed above and an additional TrailWithTimeAndCount method that have an hybrid behavior that combines both the other methods. To make the download working you have to download the Reactive Extensions from Nuget and add a reference to them in the project.

Download: http://www.silverlightplayground.org/assets/sources/SLPG.Trailing.Silverlight.zip (17 KB)