Silverlight Playground
about Silverlight and other Amenities

SilverlightShow EcoContest

2010-01-12T23:41:48+01:00 by Andrea Boschin

SilverlightShowEcoContest The team of silverlightshow.net announced today the first eco-contest. Obviously Silverlight is the focused technology but I really love the argument of the contest. The partecipants are invited to propose an application that will spread the word about climate change. After a failed of Copenaghen summit where the biggest and powerful countries have not been able to reach an agreement about the save of our planet there is for sure the need to embrace the cause and let people to be aware of this problem.

So this post would want to connect many people with the contest and hopefully with the climate changes argument. There is a great prize that I think a Silverlight enthusiast must not miss: A MIX10 invitation with hotel and travel expenses included.

The contest will end at 15 February so there is really few time to join an propose the applications. Here is the contest website:

http://contest.silverlightshow.net/

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

Writing a server-less conferencing client with Silverlight 4.0 UDP Multicast

2010-01-02T22:42:07+01:00 by Andrea Boschin

When I wrote my article about , I received many questions about writing application that communicate each other with this protocol. The reason for this request is that many people believe that Silverlight being a good platform for game developers due to its great graphical features and its simplicity, so a lot of them want to implement some kind of communication for on-line collaborative games.

Local connections have not been made for this kind of usage because them are available only for communication between application instances running in the same machine and it is not possible to use them to create gaming communications.

With Silverligth 4.0 the System.Net namespace hosts a new kind of socket communications, named UDP Multicast, that seems to be a possible solution for gaming applications but also for applications requiring fast communication between multiple clients, like conferencing applications also with video streaming support.

, also know as IP Multicast, is a well-known protocol that enables the ip infrastructure to replicate messages from multiple sources to be delivered easily to an undefined number of subscribers. The protocol works using a special class of IP addresses (224.0.0.0/4 for ipV4) where each single address represent a group of clients that is communicating each other relying on the network infrastructure for the replication of the messages. This enable the creation of client applications that do not need to have a central server where clients needs to connect using the common TCP sockets.

Like the common UDP protocol, IP Multicast is a not-connected protocol that does not guarantee the arrival of the messages and the order of delivery. So if you need a realiable channel the better is to rely on TCP sockets or you need to implement some kind of consistency check.

Writing a conferencing client

The first example I wrote to test the UDP Multicast feature is a simple conferencing client that enable people to join a multicast group and then send messages to the other members of the group.  The example you can download at the end of the article is very simplified and let the user specify an username (without checking if someone else is using the same username) and join the muklticast group. Then the user can type messages and send them to all the group members.

Silverlight 4.0 has two new classes to implement a multicast client

1) UdpSingleSourceMulticastClient let work with a single well-known source that is the unique client allowed to send to the group. This is the one-to-many communication. You can imagine to write a video source with this class and multiple clients to receive packets from it.

2) UdpAnySourceMulticastClient enables all the clients both to send and receive to or from the multicast group. This let you create something similar to a conferencing application where many-to-many connection is required.

When you use a multicast client the first thing you have to do is to join the group, using the known muticast ip address (ex: 224.0.0.1) and the port (ex: 3000). When the connection have been made you can start send and/or receive from the group. Differently from the TCP sockets with UDPMulticast you do not have a restricted set of ports to use. All the ports above of 1024 are available to the plugin.

Here is a snippet from my UDPAnySourceMulticastChannel I wrote for my example:

   1: public UdpAnySourceMulticastChannel(IPAddress address, int port, int maxMessageSize)
   2: {
   3:     this.ReceiveBuffer = new byte[maxMessageSize];
   4:     this.Client = new UdpAnySourceMulticastClient(address, port);
   5: }
   6:  
   7: public void Open()
   8: {
   9:     if (!this.IsJoined)
  10:     {
  11:         this.Client.BeginJoinGroup(
  12:             result =>
  13:             {
  14:                 this.Client.EndJoinGroup(result);
  15:                 this.IsJoined = true;
  16:                 Deployment.Current.Dispatcher.BeginInvoke(
  17:                     () =>
  18:                     {
  19:                         this.OnAfterOpen();
  20:                         this.Receive();
  21:                     });
  22:             }, null);
  23:     }
  24: }

In the constructor of the class, I've created an instance of the multicast client with the required address and port, then in the Open method I've called the BeginJoinGroup method that starts an asyncronous join request to the multicast address. As always the Silverlight's communication is asyncronous so when the callback is called I need to invoke the EndJoinGroup and then marshal the thread to the user interface with using the Dispatcher.

When the group has been joined you can start receiving and sending. This two actions are simultaneous because while you are receiving messages (or you are waiting to receive) you can also send messages to the group. So you have to invoke the BeginReceiveFromGroup method that starts listening for incoming packets and calls the callback method when something has been received. While the client is waiting for something to receive you can also call the BeginSendToGroup method to send something to the group. You have to be aware that when you send a packet to the group you will also receive the packet you sent because the multicast will replicate the message to all the joined clients.

   1: private void Receive()
   2: {
   3:     if (this.IsJoined)
   4:     {
   5:         Array.Clear(this.ReceiveBuffer, 0, this.ReceiveBuffer.Length);
   6:  
   7:         this.Client.BeginReceiveFromGroup(this.ReceiveBuffer, 0, this.ReceiveBuffer.Length,
   8:             result =>
   9:             {
  10:                 if (!IsDisposed)
  11:                 {
  12:                     IPEndPoint source;
  13:                     this.Client.EndReceiveFromGroup(result, out source);
  14:                     Deployment.Current.Dispatcher.BeginInvoke(
  15:                         () =>
  16:                         {
  17:                             this.OnReceive(source, this.ReceiveBuffer);
  18:                             this.Receive();
  19:                         });
  20:                 }
  21:             }, null);
  22:     }
  23: }
  24:  
  25: public void Send(string format, params object [] args)
  26: {
  27:     if (this.IsJoined)
  28:     {
  29:         byte[] data = Encoding.UTF8.GetBytes(string.Format(format,args));
  30:  
  31:         this.Client.BeginSendToGroup(data, 0, data.Length,
  32:             result =>
  33:             {
  34:                 this.Client.EndSendToGroup(result);
  35:             }, null);
  36:     }
  37: }

The UDPAnySourceMulticastClient class has some other interesting methods. You can send messages to the group specifing the destination so the network infrastructure will route the message to a single target. You can also block and unblock an IPAddress to prevent messages incoming from it to be received.

There is not a "Disconnect" or "Close" method but when you need to end the communication you can call the Dispose method of the client class. This will cause the pending receive to be dropped. It is important to have a flag set when the class is disposing because when the pending receive is dropped your callback is notified and you have to be aware that the client instance is not valid anymore and avoid to call the EndReceiveFromGroup method alse you will get an exception.

   1: /// <summary>
   2: /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
   3: /// </summary>
   4: public void Dispose()
   5: {
   6:     if (!IsDisposed)
   7:     {
   8:         this.IsDisposed = true;
   9:  
  10:         if (this.Client != null)
  11:             this.Client.Dispose();
  12:     }
  13: }

The client needs only to create an instance of the class an then call the Open method to join the multicast group. The channel then automatically starts listening from incoming packets and raise an event every time it detect something. So when the user hit the send button it I can call the Send() method to send a new packet and when the channel notify me about the arrival of a packet I add it to the logging listbox. I've added an AfterOpened and BeforeClose events to allow the client to send a message just after joining the group and before leaving it.

PolicyServer

Like other networking tools in Silverlight, the ip multicast requires something issuing a policy file. This is the sole server-side requirement for this protocol working fine. The policy server has to implement a two UDP messages system. The first message, sent by the client, is a datagram called "announcement" that asks the server to issue a policy file. When the server receive this message have to send an xml file that authorize to the client to communicate with a particular ip address and port. The mechanism is very similar to the TCP socket policy server but use an UDP messagging system.

To implement this server the best is downloading this project from MSDN code gallery. The project contains a working policy server that you can simply start from a console application or from a win32 service.

The drawbacks

The application I have included at the end of the article is very simple and demostrate the power of this messaging system, that was initially designed for effective video streaming. Unfortunately there is some drawbacks. First of all, also if I've entitled this example "server-less" this is true for the 99%. You need a policy issuer that is a little server, but it is not crucial for performance concerns. The system is really simpler than an always-connected TCP implementation and due to the nature of the UDP protocol really require less resources.

Another concern is about the security and realiability. The UDP protocol does not implements some infrastructure to avoid the ip spoofing and does not guarantee the packet delivery and the arrival order. In a real world solution you have to be aware of these limitation and take care of them. You have to write code to sign packets to know from whom they are issued and to handle packet loss and unordered delivery. This may be someway complex, but is a little price to pay for the effectiveness of this protocol.

Finally, the major drawback is that the most common firewalls manage to block this kind of traffic. If using a TCP socket server on a well known port is someway difficult due to the need of having firewall configurations, implementing a multicast is probably more complex specifically if you need to send the packets through the Internet. So in my opinion the most common scenario for this protocol to work is a local area network where you can manage to have firewalls and network infrastructure comply with it.

Download: SilverlightPlayground.UDPMulticast.zip (181 KB)

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

A generic ViewModel to publish sets of objects

2009-12-16T22:14:18+01:00 by Andrea Boschin

The programming with the MVVM pattern often requires a proliferation of types because there are more Views that need a ViewModel than you might think. You can think that you need to associate a ViewModel only to simple blocks of your user interface, but while you are writing code you often understand that there are other cases where a ViewModel is required.

As an example while populating a DataGrid binding simple entities to the grid is not  good idea. A single row of a grid not only contains some data to be displayed but often may contain some commands, a link to be clicked, a button to delete an item and so on.

All these are cases where you need a ViewModel to correcty handle the binding and the related commands. So you have to create a new type, add a bunch of properties and some commands and finally populate the grid with instances of the new type. Then you will find someway difficult to route the command from the child ViewModel to the one that has generated it.

Simple is better.

In my recent applications I found a reasonable workaround that correctly handle the situation but avoid a proliferation of classes and as usual in this cases the solution comes from a generic type. The trick comes from the understanding that often in this scenario you have some properties of an entity to be binded and one or two commands to be raised. And in the most cases the command have to be handled by a parent ViewModel. Imagine to have a collection which is shown in a DataGrid and a delete command on each row; To remove the row, the command has to be catched by the ViewModel which is exposing the collection. So I decided to create a simple class named RowViewModel this way:

   1: public class RowViewModel<T,K> : ViewModel
   2:     where T : ViewModel
   3: {
   4:     /// <summary>
   5:     /// Initializes a new instance of the RowViewModel class.
   6:     /// </summary>
   7:     /// <param name="parent">The parent.</param>
   8:     /// <param name="payload">The payload.</param>
   9:     public RowViewModel(T parent, K payload)
  10:     {
  11:         this.Parent = parent;
  12:         this.PayLoad = payload;
  13:     }
  14:  
  15:     /// <summary>
  16:     /// Gets or sets the parent.
  17:     /// </summary>
  18:     /// <value>The parent.</value>
  19:     public T Parent
  20:     {
  21:         get { return this.GetValue<T>("Parent"); }
  22:         set { this.SetValue<T>("Parent", value); }
  23:     }
  24:  
  25:     /// <summary>
  26:     /// Gets or sets the pay load.
  27:     /// </summary>
  28:     /// <value>The pay load.</value>
  29:     public K PayLoad
  30:     {
  31:         get { return this.GetValue<K>("PayLoad"); }
  32:         set { this.SetValue<K>("PayLoad", value); }
  33:     }
  34: }

To simplify the creation of the collection property I've created a class RowViewModelCollection that inherits from the ObservableCollection. This allow me to declare the observable properties with a less verbose syntax:

   1: public class RowViewModelCollection<T, K> : ObservableCollection<RowViewModel<T, K>>
   2:     where T : ViewModel
   3: { }

Now we are ready to publish a DataGrid using this class. The RowViewModel exposes T as the parent ViewModel and K as the payload. This is the entity we want to display in the grid. So we can write a XAML similar to this:

   1: <data:DataGrid ItemsSource="{Binding Tasks}">
   2:     <data:DataGrid.Columns>
   3:         <data:DataGridTemplateColumn>
   4:             <data:DataGridTemplateColumn.CellTemplate>
   5:                 <DataTemplate>
   6:                     <HyperlinkButton cmd:Click.Command="{Binding Parent.DeleteTaskCommand}"
   7:                                      cmd:Click.CommandParameter="{Binding PayLoad}"
   8:                                      HorizontalAlignment="Center" VerticalAlignment="Center" >
   9:                         <Image Height="16" HorizontalAlignment="Center" VerticalAlignment="Center" Width="16" Source="/Elite.TimeTracker.Client;Component/Images/delete.png" Stretch="Fill"/>
  10:                     </HyperlinkButton>
  11:                 </DataTemplate>
  12:             </data:DataGridTemplateColumn.CellTemplate>
  13:         </data:DataGridTemplateColumn>
  14:         <data:DataGridTextColumn Header="Cliente" Binding="{Binding PayLoad.Customer.Description}" />
  15:         <data:DataGridTextColumn Header="Ora" Binding="{Binding PayLoad.StartTime}" />
  16:         <data:DataGridTextColumn Header="Descrizione" Binding="{Binding PayLoad.Description, Converter={StaticResource ellipsis}}" />
  17:         <data:DataGridCheckBoxColumn Header="Chiam." Binding="{Binding PayLoad.IsPhoneCall}" />
  18:         <data:DataGridCheckBoxColumn Header="Compl." Binding="{Binding PayLoad.IsCompleted}" />
  19:     </data:DataGrid.Columns>
  20: </data:DataGrid>

In a couple of words we have:

ItemsSource="{Binding Tasks}" - This connect the DataGrid to a RowViewModelCollection declared in the parent ViewModel.

Binding="{Binding PayLoad.StartTime}" - This take advantage of the dot syntax of the DataBinding that allow to access complex properties of the binded objects. Remember that PayLoad is the instance of the entity to bind to the DataGrid so PayLoad.StartTime binds the StartTime property to the cell.

cmd:Click.Command="{Binding Parent.DeleteTaskCommand}" - This binds the click event of the HyperlinkButton to a command of the parent ViewModel.

cmd:Click.CommandParameter="{Binding PayLoad}" - This binding let me pass the entire entity the delegate command.

This tecnique simplifies the code required to handle the DataGrid. When a command is raised the parent ViewModel handle it and this reduce the need to use an EventBroker, and it gives a more simple and maintainable code.

Is this good only for DataGrids?

There are a lot of cases where you have to bind a collection to a control, the ItemsControl, the ListBox, and so on. Every time you encounter one of these cases you can obviously apply this tecnique. Of course it is useful only if you need to handle some commands, otherwise you can simply bind the entity directly to the control.
In the code I've attached to a my previous post - the -you can find a working sample of the workaround. 

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

Silverlight 4.0 beta released

2009-11-18T18:22:15+01:00 by Andrea Boschin

Download Sample Code: SilverlightPlayground.SL4BetaTestConsole.zip (89K)

 

During the Keynote of the PDC 2009 a new beta of Silverlight has been announced and made available. I think very few people did expect the early release of the version 4.0, and if you think in terms of number of new features compared with the time passed since the RTW of Silverlight 3.0 - only four months - you understand the big work made by one of the most prolific teams of Microsoft.

In the latest month I could play with the beta bits, and I've compiled a collection of the most important features coming in this release, to understand how them works and to release some working code to let people easily learn them. This collection is linked at the end of this post in the form of a self-explaining navigation application. The application contains eleven samples that show the features I list below:

Full Trust in Out of Browser: While detaching an application to out of browser now it is possible to give full trust to the installed application. This enable huge improvements: no need of cross domain policies, access to file system, no user-initiated dialogs. You can also use COM interoperability.

WebCam: Silverlight 4.0 introduce some new API to handle video and audio capture. This sample shows how to use the CaptureSource class to detect video devices and to capture live stream and snapshots from it. The same pattern can be used to capture audio sources

WebBrowser: This new control has been added to the Silverlight bits to enable the use of html hosting into Silverlight applications. The WebBrowser control is available only when the application is running out of browser so before running the sample you need to install the application

RichTextArea: Another new control let the user enter formatted code. The RichTextArea behave like a TextBox but it can host fonts, weights, styles, and entering graphic elements and links like you can do with a text editor. The sample show also how to read the content of the RichTextArea you can populate with XAML markup.

HTML Brush: Like using a media element to publish a video on a brush with the HtmlBrush it is possible to use the output of a WebBrowser control to render the brush. The use of this feature has some limits but the code works fine.

PrintDocument: In the development of Line of Business applications, sending documents to the printer is an useful feature. Silverlight 4.0 introduce a new PrintDocument that enable sending elements of the Visual Tree to the printer.

Righ Mouse Button: In the previous releases the context menu of Silverlight prevent the use of the Right mouse button. In this release you can intercept this button and attach the logic you need. In the sample you can use left and right buttons to change the size of the circle. If you click outside the circle the normal context menu will be displayed.

DataBinding to DependencyObject: In the current version the DataBinding between elements is available only when the target inherits from FrameworkElement. This limit prevent, as an example, to bind multiple a RotateTransform to a single Slider. In Silverlight 4.0 this limit has been overcome and now it is possible to bind DependencyObjects. This is a great step in the compatibility with WPF.

Improvements to Binding: The binding markup extension has been enriched with a new set of properties which simplify the development. This include StringFormat, FallbackValue and TargetNullValue.

Commands: The controls inheriting from ButtonBase has acquired two new properties, Command and CommandParameter. It is a tiny step in the direction of MVVM programming.

Drag & Drop: With this release it is possible to detect dragging of elements on the application surface. The sample read the filename, la last access date and the size of the stream.

Notification Window: Desktop application can show a popup in the tray bar of Windows. This now is available also in Silverlight out of browser applications.

These are a huge set of features for the short period of time where they were developed. I hope many of you will find useful the code I've linked to this post. If you need help to understand the samples feel free to contact me through the contact form.

Download: SilverlightPlayground.SL4BetaTestConsole.zip (89K)

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

My Model-View-ViewModel exercise

2009-11-13T01:32:04+01:00 by Andrea Boschin

Senza-titolo-1 Some weeks ago I've worked on an exercise originally started to try writing a complete application with full Model-View-ViewModel pattern. I've created the application with Visual Studio 2008, Prism to integrate missing features and Ria Services July CTP to get access to a SQL Server 2008 Database.

The application is a little time tracker, and I've decided to attach it to this post because it was very useful to me to understand problems and missing things about the MVVM pattern.

In the next days I will write some words about these problems I found, but for now I only want to undisclose the application to let something download it and give me some comments about it.

If you decide to try the application remember to attach the database mdf in the zip file, to set the connection strings in the web.config and the credentials for reporting services if you want to setup it and finally enter "tracker" as username and p@ssw0rd as password.

I'm currently learning this pattern and I do not want to consider my implementation complete, perfect and without any error. So please let me know what do you think and how can I improve it. Thanks in advance.

Download: Elite.TimeTracker.zip (~820 Kb)

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

How to configure an AuthenticationDomainService using Ria Services Class Library

2009-11-06T11:36:01+01:00 by Andrea Boschin

Using a Ria Services Class library to collect DomainServices and DomainContexts in a solution is a good practice because everyone know the value of having classes separated in projects instead of having them in the web project.

If you try to create this kind of project and then you add an Authentication Domain Service with the July 2009 CTP of Ria Services you will find two major drawbacks. First of all you will notice the generated code does not contains a RiaContext class. RiaContext is the class responsible to handle the User and roles and configure the type of Authentication to use in the application.

To workaround to this problem you may simply write by hand this class and put it in the client side part of the Ria Services library project. The code can be copied by an AuthenticationDomainContext generated in the web project but it is very simple and I show you the code here:

   1: public sealed partial class RiaContext : System.Windows.Ria.RiaContextBase
   2: {
   3:     #region Extensibility Method Definitions
   4:  
   5:     partial void OnCreated();
   6:  
   7:     #endregion
   8:  
   9:     public RiaContext()
  10:     {
  11:         this.OnCreated();
  12:     }
  13:  
  14:     public new static RiaContext Current
  15:     {
  16:         get
  17:         {
  18:             return ((RiaContext)(System.Windows.Ria.RiaContextBase.Current));
  19:         }
  20:     }
  21:  
  22:     public new User User
  23:     {
  24:         get
  25:         {
  26:             return ((User)(base.User));
  27:         }
  28:     }
  29: }

With this class you can configure the Authentication Domain Context as you did with the generated class. So you have to add it to the App.config, in the ApplicationLifetimeObjects tag and then add a kind of authentication like the WindowsAuthentication and FormsAuthentication.

The second drawback is that if you run the project this way and then you call the Login() method (or any other method) of the RiaContext you will get an error:

The DomainContextType is null or invalid and there are no contexts generated from AuthenticationBase<T>

This probably come from the fact that the RiaContext is not correctly initializated so when the class search for a valid domaincontext to handle the Login call it fails because it does not find it. The tip to correct this behavior is to specify the DomainContext property in the Authentication you have choosed. Here is how to change the App.xaml file:

   1: <Application.ApplicationLifetimeObjects>
   2:     <slpgria:RiaContext>
   3:         <slpgria:RiaContext.Authentication>
   4:             <appsvc:FormsAuthentication>
   5:                 <appsvc:FormsAuthentication.DomainContext>
   6:                     <slpgdc:MyAuthenticationDomainContext />
   7:                 </appsvc:FormsAuthentication.DomainContext>
   8:             </appsvc:FormsAuthentication>
   9:         </slpgria:RiaContext.Authentication>
  10:     </slpgria:RiaContext>
  11: </Application.ApplicationLifetimeObjects>

As you can see you have simply to give an instance of the generated Authentication Domain context class to the FormsAuthentication (or Windows Authentication as well). The RiaContext need to have this instance to make the calls to the BL methods in the Domain Service.

I really do not know if this behavior will be corrected in the next releases of RiaServices. The solution is pretty simple but take me some hours to understand what are going wrong. So I hope this may help you to spare some time making your experiments with the current release.

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

Handling duplicated connections on Polling Duplex

2009-10-23T00:46:00+01:00 by Andrea Boschin

The last tip I would like to propose is a tecnique to avoid a single client machine connect multiple times to the same polling server. This may be the case when the user starts two or more instances of the browser or open the same page in multiple tabs. In this scenario may be unuseful to have every page connected to the server.

In Silverlight 3.0 there is a way to check when a plugin has been loaded many times. When you try to create a LocalReceiver with the same name from two instances you get an exception because they cannot share the same name. So using a LocalReceiver you can check if another browser is open.

   1: public override void Start()
   2: {
   3:     LocalMessageReceiver receiver = this.CreateReceiver();
   4:  
   5:     if (receiver != null)
   6:     {}  // receiver created: I'm the master...
   7:     else
   8:     {}  // cannot create receiver: I'm a slave...
   9: }
  10:  
  11: private LocalMessageReceiver CreateReceiver()
  12: {
  13:     try
  14:     {
  15:         LocalMessageReceiver receiver = new LocalMessageReceiver("PollingReceiver");
  16:         receiver.Listen();
  17:         return receiver;
  18:     }
  19:     catch(ListenFailedException)
  20:     {
  21:         return null;
  22:     }
  23: }

 

Checking the presence of another instance is only half of the work to do. When you detect you are a slave in the machine you need to avoid connecting - slave does nothing because a master already exists - and probably you have to change the user interface to let the user know that there is another instance running.

In my application I need to check the presence of the master every few seconds to let a slave becoming a master. To do this I've created two classes MasterPollingClientCode  SlavePollingClientCore implementing the same interface IPollingClientCore. The first class connect to the server and the other class simply does nothing.

   1: public override void Start()
   2: {
   3:     LocalMessageReceiver receiver = this.CreateReceiver();
   4:  
   5:     if (receiver != null)
   6:         this.Core = new MasterPollingClientCore(this.SessionId, this.EndPoint, receiver);
   7:     else
   8:         this.Core = new SlavePollingClientCore(this.LocalId, 
                          new LocalMessageSender("PollingSender" + this.LocalId.ToString()));
   9:  
  10:     this.Core.AlarmReceived += new EventHandler<NotifyAlarmReceivedEventArgs>(Core_AlarmReceived);
  11:     this.Core.Connected += new EventHandler(Core_Connected);
  12:     this.Core.Disconnected += new EventHandler(Core_Disconnected);
  13:     this.Core.Fault += new EventHandler<PollingFaultEventArgs>(Core_Fault);
  14:     this.Core.Start();
  15:     base.Start();
  16: }
 

The container class, then starts a thread. This thread try to create a new LocalReceiver and when it is able to get an instance it change the core class from slave to master and connect to the server. This way the client is always connected to the server with alwasy one simple connection:

   1: protected override void ThreadProc()
   2:     {
   3:         Debug.WriteLine("ThreadProc");
   4:  
   5:         while(WaitHandle.WaitTimeout == WaitHandle.WaitAny(this.ExitHandles, 5000))
   6:         {
   7:             if (this.Mode != PollingClientMode.Master)
   8:             {
   9:                 Deployment.Current.Dispatcher.BeginInvoke(
  10:                     ()=> this.TryConvertToMaster());
  11:             }
  12:         }
  13:     }
  14:  
  15:     /// <summary>
  16:     /// Tries the convert to master.
  17:     /// </summary>
  18:     private void TryConvertToMaster()
  19:     {
  20:         Debug.WriteLine("TryConvertToMaster");
  21:  
  22:         LocalMessageReceiver receiver = this.CreateReceiver();
  23:  
  24:         if (receiver != null)
  25:         {
  26:             Debug.WriteLine("created");
  27:  
  28:             // detach all
  29:             this.Core.Stop();
  30:             this.Core.AlarmReceived -= new EventHandler<NotifyAlarmReceivedEventArgs>(Core_AlarmReceived);
  31:             this.Core.Connected -= new EventHandler(Core_Connected);
  32:             this.Core.Disconnected -= new EventHandler(Core_Disconnected);
  33:             this.Core.Fault -= new EventHandler<PollingFaultEventArgs>(Core_Fault);
  34:             // create new core
  35:             this.Core = new MasterPollingClientCore(this.SessionId, this.EndPoint, receiver);
  36:             // attach all
  37:             this.Core.AlarmReceived += new EventHandler<NotifyAlarmReceivedEventArgs>(Core_AlarmReceived);
  38:             this.Core.Connected += new EventHandler(Core_Connected);
  39:             this.Core.Disconnected += new EventHandler(Core_Disconnected);
  40:             this.Core.Fault += new EventHandler<PollingFaultEventArgs>(Core_Fault);
  41:             this.Core.Start();
  42:         }
  43:     }
 
 

If you are brave you can try to implement a communication between Slave and Master using a LocalSender. Using the code I provider this task cannot be too hard.

Good Work

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

How to avoid flooding a PollingDuplex server

2009-10-06T14:37:39+01:00 by Andrea Boschin

Returning on the PollingDuplex argument, today I would like to illustrate a tecnique I used to avoid the flooding in my Polling Duplex service. The problem come from the fact that my server retain a list of connected clients and is unable to detect the disconnection in a short time. After a while the notification from the server to the disconnected client will timeout so the server handle the timeout and remove the client from its list. But if for some reason a client Register itself multiple times the server notification list will grow and this may become a problem causing the service to slow down its response time.

In a recent project I have to address this issue because of the way the polling client works. Imagine having a instant messaging client using PollingDuplex in all the pages of a portal. When the user navigate in the website the polling client will repeatly connect and disconnect from the polling server because the user may change page after short time.

How to generate a persistent ClientID

To handle this problem I need to have a globally unique id identifing the connecting client. If the ID is unique across different connected clients the server can use this ID to search previuos instances of the client in his notification list and if found it discart the old client and replace it with the new one. The solution is pretty simple but it require the ability to generate a very unique id (obviously a Guid) and then persist it across different browser session.

The trick is to use the Isolated Storage. The first time I start the client it generate the Guid and save it in the IsolatedStorageSettings collection. Then it use the guid to connect and register to the polling server.

All the other times the client find the Guid in the IsolatedStorageSettings and avoid to generate another Guid but use the old identifier. Here is the code to generate the guid or take id from the storage:

   1: private void Application_Startup(object sender, StartupEventArgs e)
   2: {
   3:     Guid key;
   4:  
   5:     if (!IsolatedStorageSettings.ApplicationSettings.Contains("InstanceKey"))
   6:     {
   7:         key = Guid.NewGuid();
   8:         IsolatedStorageSettings.ApplicationSettings["InstanceKey"] = key;
   9:         IsolatedStorageSettings.ApplicationSettings.Save();
  10:     }
  11:     else
  12:         key = (Guid)IsolatedStorageSettings.ApplicationSettings["InstanceKey"];
  13:  
  14:     this.RootVisual = new MainPage(key.ToString());
  15: }

I put the code in the Application_Startup method then I pass the key to the MainPage constructor because it must use the guid to connect to the server.

On the server side I've slightly changed the Register method and the Polling thread to handle the new guid. First of all I request the id in the Register method:

   1: public void Register(string sessionId)
   2: {
   3:     IPollingServiceClient client =
   4:         OperationContext.Current.GetCallbackChannel<IPollingServiceClient>();
   5:  
   6:     PollingMonitor.Current.Register(client, sessionId);
   7: }

Then the server checks his notification list to add or change the callback client:

   1: /// <summary>
   2: /// Adds the specified item.
   3: /// </summary>
   4: /// <param name="item">The item.</param>
   5: public void Add(IPollingServiceClient client, string sessionId)
   6: {
   7:     var found = (from c in this
   8:                  where c.SessionId == sessionId
   9:                  select c).SingleOrDefault();
  10:  
  11:     if (found != null)
  12:         found.ChangeClient(client);
  13:     else
  14:         this.Add(new PollingClient(client, sessionId));
  15: }

The ChangeClient() method simply put the new callback client in the object instance representing the client in the list.

There are only two drawbacks in this tecnique. The first is that the user can clear his IsolatedStorage using the Silverlight context menu. This deletes the saved Guid so the next time the client connect to the server it generate another Guid. On the other side someone may discover some privacy concerns on having an id globally identifying the client because this may become a way to track the user activities. You have to be aware of this problem and eventually you can mitigate the problem using a TTL to invalidate the Guid after some hours or days so the client will change the Guid and the tracking become hardest.

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

Handling faults on PollingDuplex while server is not available

2009-09-25T15:57:34+01:00 by Andrea Boschin

During the development of the project I'm currently working I've implemented a polling duplex client and I found some improvements to the code I've published some weeks ago in this post.

The problem I would like to answer here is caused by server unavailability that may origin in many causes. In my scenario I'm using a WCF service hosted by Internet Information Server. While I'm using a server-side thread running in the context of the Application Pool there may be some conditions where Application Pool is recycled so the server thread is aborted and the PollingDuplex communication stops.

There is many reasons why we have to avoid this condition. In my case it is important that the client continue receive updates from the polling server without it require a page refresh from the user. So I've implemented a fault handling procedure that let my client detect when the server become unavailable and then it retry connecting and restart server side thread.

First of all we have to write a registration procedure. My duplex channel work using a Register() ServiceOperation called by the client that subscribe the client in the server thread for updates notification. The client callback contract has a single NotifyAlarm() method used by the server to notify messages to client. Here is the client-side code I use to start the polling:

   1: /// <summary>
   2: /// Registers this instance.
   3: /// </summary>
   4: private void Register()
   5: {
   6:     this.Client = new PollingServiceClient(
   7:         new CustomBinding(
   8:             new PollingDuplexBindingElement
   9:                 {
  10:                     InactivityTimeout = new TimeSpan(1, 0, 0),
  11:                     ClientPollTimeout = new TimeSpan(0, 1, 0)
  12:                 },
  13:             new BinaryMessageEncodingBindingElement(),
  14:             new HttpTransportBindingElement()),
  15:         this.EndPoint);
  16:  
  17:     this.Client.NotifyAlarmReceived += 
  18:         new EventHandler<NotifyAlarmReceivedEventArgs>(Client_NotifyAlarmReceived);
  19:     this.Client.InnerChannel.Faulted += 
  20:         new EventHandler(Client_Faulted);
  21:     this.Client.RegisterCompleted += 
  22:         new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(Client_RegisterCompleted);
  23:     this.Client.RegisterAsync(this.SessionId);
  24: }

To handle channel fault I subscribe the Faulted event in the InnerChannel. I cannot find any other way to detect when the polling fail due to server unavailability. If you trace the polling of the client and then simulate the server unavailability, recycling the application pool you will see a 404 error (if you use ClientHttpStack the error will be more specific).

Untitled

When this error occur the InnerChannel.Faulted event is raised so you can restart the polling calling the Register() method again. In the Faulted event handler I simply call the Register method again. 

   1: /// <summary>
   2: /// Handles the Faulted event of the Client control.
   3: /// </summary>
   4: /// <param name="sender">The source of the event.</param>
   5: /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
   6: void Client_Faulted(object sender, EventArgs e)
   7: {
   8:     Deployment.Current.Dispatcher.BeginInvoke(
   9:         () =>
  10:         {
  11:             this.OnDisconnected();
  12:             this.Register();
  13:         });
  14: }

The better will be starting a Timer to retry connection on a regular timeout to let the client returning online after longer server unavailability. This may be useful also when we start the polling because we can dowload the Silverlight application from a server but then it starts the polling to another server. So I've added some code in the RegisterCompleted event handler and when I get an exception from the Register() method I start a separate thread. It waits for 60 seconds then recall the Register() method again.

   1: void Client_RegisterCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
   2: {
   3:     if (e.Error == null)
   4:         this.OnConnected();
   5:     else
   6:     {
   7:         this.OnFault(e.Error);
   8:  
   9:         ThreadPool.QueueUserWorkItem(
  10:             (o) =>
  11:             {
  12:                 Thread.Sleep(60000);
  13:  
  14:                 Deployment.Current.Dispatcher.BeginInvoke(
  15:                     () => this.Register());
  16:             });
  17:     }
  18: }

You have to be aware that the Faulted event require you to marshal the context of the thread before updating any UI element. In my code I raise an event of a wrapper object to let UI reflect the temporary disconnection. So I have to use the Dispatcher to marshal the Thread to the UI.

This is all for now. I will write more on this argumet on the next days to handle a different condition.

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

A Prism (Unity) Service to create Views

2009-08-31T21:10:03+01:00 by Andrea Boschin

After a long summer pause I’m back with this new post. This time I want to investigate an aspect of the Model-View-ViewModel pattern programming with Silverlight. During the summer I've started working on an application where I used Prism to implement MVVM and I found useful to write some code to easily create instance of views during application inizialization and during its lifetime. I really do not know if this is the better solution but I found it easy and useful so I've decided to share it with you. Let me say in this post I assume you are already aware of the reasons and benefits coming from the usage of the popular Model-View-ViewModel pattern and how the pattern works. I also assume you have a minimal knowledge of the Prism toolkit and Unity.

The relationship between the View and the ViewModel

In this section I would like to depict how the View and ViewModel collaborate and what we have to do to create an instance of a View and of its own ViewModel at the sole purpose of preparing the field for explaining my solution.

In the MVVM pattern the View represent the user interface and the ViewModel represent the business logic required to drive the informations displayed on the View. This way, every time we have to create a View we also have to create a specific ViewModel exposing the expected informations to be displayed. The ViewModel is not aware of the View, so It does not know how its properties are consumed, but it simply publish some data through some properties and the View will attach these properties using DataBinding.

What I've said reveal almost two things. The first is that the View does not know how the ViewModel works internally, but it have to know the structure of its surface. In other words the ViewModel have to implement a given well-known "interface" to let the View working fine. This interface contains only properties the View is expected to attach. This implementation is not truly required by the pattern but we can think it is near to reality.

The other thing we have to know is that to let the view binding to the ViewModel, we have to put the ViewModel in the DataContext of the View. So, the creation of the View involve the creation of a specific ViewModel -possibly implementing a given interface - and the assignment of this instance to the DataContext property of the View. Translating this concept in code we have to write something like this:

   1: MyView view = new MyView() 
   2: { 
   3:     DataContext = new MyViewModel() 
   4: }; 


In my projects I do not like to write this code because it does not let me impose to the ViewModel an interface implementation. I can obviously implement the interface but there is nothing checking that this implementation has been done. To avoid this problem I've decided to create a service I use every time I need to create a View. The service is responsible to check that the ViewModel implements a specific interface. So the creation of a View become this:

   1: // assuming "vbs" is an instance of the service 
   2: MyView view = vbs.CreateView<MyView>(); 

What is a service?

Before entering the service implementation details, I would like to explain what is a Service. As I've already said in the previous paragraphs I'm using , a.k.a . Prism is a collection of useful tools to let the developer apply easily the most common architectural patterns. For the purpose of this article we will use , a dependency injection container recently ported to Silverlight from the Microsoft Pattern and Practice team. It is available inside the Prism collection.

Unity is an "" container. It let you create and register instances of classes - giving them a lifetime manager responsible of how and when the class is created and destroyed - and then locate these classes when you need to use them. Creating a class and registering it in the IOC container let you having something similar to a service, always available and discoverable, you may dedicate to specific responsibility.

The purpose of Unity is to promote layer decoupling to enable unit testing of the applications, but this is out of the scope of this article. If you would like to read something about this argument please refer to the Unity home page on codeplex: http://www.codeplex.com/unity.

Anatomy of the ViewBuilderService

Now that I have briefly explained how a service works it is time to explain the basis of my ViewBuilderService. The trick is that the View have to declare somewhere the interface it expects the ViewModel to implement. We may have an interface "IMyViewModel" and a view "MyView" that can consume a ViewModel implementing this interface. Using a simple custom attribute we can decorate the View codebehind with the interface:

   1: [ViewModel(typeof(IMyViewModel))]
   2: public partial class MyView : UserControl
   3: {
   4:     public MyView()
   5:     {
   6:     }
   7: }

Declaring a custom Attribute is simple and it enable the ViewBuilderService to discover the interface to search for in the IOC container. In the next box there is the declaration of the ViewModelAttribute where I use the AttributeUsage attribute to inform the compiler where it have to expect the attribute to be applied.

   1: [AttributeUsage(AttributeTargets.Class)]
   2: public class ViewModelAttribute : Attribute
   3: {
   4:     public Type ViewModelType { get; set; }
   5:  
   6:     public ViewModelAttribute(Type viewModelType)
   7:     {
   8:         this.ViewModelType = viewModelType;
   9:     }
  10: }

To connect a ViewModel to its own interface we need to create the ViewModel and register it into the IOC container. This way the ViewBuilderService can read the ViewModelAttribute on the View and ask the container to resolve the interface and give us the ViewModel instance to put in the DataContext. The best place to register the ViewModels is a Module we have declared in the Unity Bootstrapper. In the sample attached to this article I've omitted to use a Module for the purpose of not complicate the sample. So the ViewModels are registered in the Bootstrapper itself.

   1: /// <summary>
   2: /// Registers the types.
   3: /// </summary>
   4: private void RegisterTypes()
   5: {
   6:     this.Container.RegisterType<IMyViewModel, MyViewModel>();
   7: }

Now all is ready and we can create the service. We have to remember that the service has to be registered in the IOC contained to be discoverable using the ServiceLocator. So we start creating a class that implements an interface IViewBuilderService:

   1: public class ViewBuilderService : IViewBuilderService
   2: {
   3:     private static IUnityContainer TheContainer { get; set; }
   4:  
   5:     public ViewBuilderService (IUnityContainer theContainer)
   6:     {
   7:         this.TheContainer = theContainer;
   8:     }
   9: }

The IViewBuilderService interface have to expose only a CreateView<T>() method we will implement in the service. This method is responsible of finding the ViewModel in the container, creating the View we specified in the T parameter and finally connect view and viewmodel together.

   1: public T CreateView<T>()
   2:     where T : UserControl, new()
   3: {
   4:     ViewModel vm = this.GetViewModel(typeof(T));
   5:     return new T() { DataContext = vm };
   6: }
   7:  
   8: private ViewModel GetViewModel(Type viewType)
   9: {
  10:     ViewModelAttribute attribute = 
  11:         viewType
  12:             .GetCustomAttributes(typeof(ViewModelAttribute), true)
  13:             .OfType<ViewModelAttribute>()
  14:             .SingleOrDefault();
  15:  
  16:     if (attribute == null)
  17:         throw new InvalidOperationException("Missing ViewModelAttribute");
  18:  
  19:     ViewModel vm = this.TheContainer.Resolve(attribute.ViewModelType) as ViewModel;
  20:  
  21:     if (vm == null)
  22:         throw new InvalidOperationException("Cannot Resolve ViewModel");
  23:  
  24:     return vm;
  25: }

Using the ViewBuilderService

It is time to use the service inside our applications. First of all we have to register the service into the IOC container. We can register the service like we already have registered the ViewModel using the RegisterType method. While we can use the same instance of the service in all the application we can use a ContainerControlledLifetimeManager. This type of lifetime manager will transform the service in a singleton instance.

   1: /// <summary>
   2: /// Registers the types.
   3: /// </summary>
   4: private void RegisterTypes()
   5: {
   6:     this.Container.RegisterType<IViewBuilderService, ViewBuilder>(
   7:         new ContainerControlledLifetimeManager());
   8:  
   9:     this.Container.RegisterType<IMyViewModel, MyViewModel>();
  10: }

Then now using the ServiceLocator we can discover the service when we need to create a View. The ServiceLocator is a Singleton class, that is capable to search registered types by its interface and return an instance. You can use the ServiceLocator everywhere you need to find the IViewBuilderService.  Here is the code to create a View and assign to the Shell:

   1: Grid grid = this.Shell.FindName("LayoutRoot") as Grid;
   2:  
   3: if (grid != null)
   4: {
   5:     IViewBuilderService vbs =
   6:         ServiceLocator.Current.GetInstance<IViewBuilderService>();
   7:  
   8:     MyView view = vbs.CreateView<MyView>();
   9:  
  10:     grid.Children.Add(view);
  11: }

Obviously I could use the RegionManager to put the new View into the user interface but I wanted to keep the example simple.

All the code I've tryied to explain in this post is attached at the end of the article. I hope you will find it useful in your applications and I will expect comments from you to improve my design and know your opinion about it.

Download: SilverlightPlayground.ViewBuilderService.zip (~430 kb)

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

Use CollectionViewSource effectively in MVVM applications

2009-07-18T23:13:15+01:00 by Andrea Boschin

In a my I've outlined the new CollectionViewSource introduced in silverlight with the latest release. This control is really useful while we need to sort and filter collection of objects in memory, but if we need to use a Model-View-ViewModel pattern to develop our application there is some problems using the control.

To implement the MVVM pattern we need to inject a ViewModel into the View using the DataContext property. This is usual in this kind of application because we need to bind the properties of the ViewModel to the controls in the View. So if we need to use a CollectionViewSource we can try to bind a collection from the ViewModel to the CVS and then bind the control to the CVS itself. Unfortunately this approach does not work because we cannot bind the CVS directly to the DataContext of the page. Trying to do this operation we will get a AG_E_BAD_PROPERTY_VALUE exception because the control does not inherits from FrameworkElement so it does not support DataBinding.

However, if it were possible, the CollectionViewSource would force us to put a lot of code in the codebehind to handle the Filter event and the sorting property. So, we have to follow another way to use the CollectionViewSource effectively with this kind of applications.

How to use the CollectionViewSource

The only way to use the CollectionViewSource with the MVVP pattern is to expose it as the type of the bindable property. This way we can manage the properties of the CVS and handle the Filter event from inside the ViewModel without putting anything in the codebehind of the View.

First of all we have to create two properties in the ViewModel. The first property will be the ObservableCollection<T> and we will populate it with the data to display. This property can be private because it will be used only to feed the ColectionViewSource of the second property. Here is how to initialize the properties:

   1: /// <summary>
   2: /// Gets or sets the names.
   3: /// </summary>
   4: /// <value>The names.</value>
   5: public CollectionViewSource Names { get; set; }
   6:  
   7: /// <summary>
   8: /// Gets or sets the names internal.
   9: /// </summary>
  10: /// <value>The names internal.</value>
  11: private ObservableCollection<string> NamesInternal { get; set; }
  12:  
  13: /// <summary>
  14: /// Initializes a new instance of the <see cref="MainPageViewModel"/> class.
  15: /// </summary>
  16: public MainPageViewModel()
  17: {
  18:     this.NamesInternal = new ObservableCollection<string>();
  19:     this.Names = new CollectionViewSource();
  20:     this.Names.Source = this.NamesInternal;
  21:  
  22:     // populate the ObservableCollection
  23:     foreach (string item in DataSource.GetNames())
  24:         this.NamesInternal.Add(item);
  25: }

Now, to bind the CollectionViewSource in the XAML we have to rely on his View property. If we put a reference to the CVS in the property ItemsSource in the XAML it simply will not work. Here is how to correctly bind:

   1: <ListBox ItemsSource="{Binding Names.View}" Margin="5,5,5,1" Grid.ColumnSpan="4" />

Once we have connected the CVS to the collection and the UI to the CVS we can handle the commands from the View and interact with the CVS to modify how to display the data. In the sample I have a togglebutton that is raising a ChangeSortDirectionCommand. I use the DelegateCommand<T> from Prism V2.0 and when someone send the command I change the SortDescriptor in the CollectionViewSource.

In the same View the TextChanged event is raised when the user type in the textbox. This command handled by the ViewModel let the CVS refresh itself. This way the Filter event will be evaluated again and the View will be updated with the filter applied.

I've attached to the post a new version of the sample I've proposed with the first article. Now the sample use the MVVM pattern with the CollectionViewSource.

Download: Elite.Silverlight3.CollectionViewMVVM.zip (~520 KB)

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

Silverlight 3.0 RTW: The CollectionViewSource

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

Since the first release of WPF the framework contains a component called CollectionViewSource. The CollectionViewSource allow developer to apply sorting, filtering and grouping to in-memory collections of objects. This component is very useful when small collections (up to hundreds of items) is loaded in memory and need to give a better experience to the user.

Some months ago I of the CollectionViewSource for Silverlight 2.0. I worked hard to implement the component and finally I published a version with the only limitation of not allowing grouping. While sorting and filtering are implemented directly on the data seamless, the grouping require an infrastructure to be consumed (grouping support in ItemsControl) that I was unable to provide.

The new release of Silverlight 3.0 RTW comes with an implementation of this component that fill this hole but it has the same limitations of my CollectionViewSource. This limitations come from the same reason I cannot implement by myself: the missing grouping support in ItemsControls. However the native component has a some advantages on mine, first of all a very strict compatibility with the architecture of the WPF CollectionViewSource. In this post I will show you how to configure and use the component in a Silverlight application.

Using the CollectionViewSource

The Silverlight CollectionViewSource is a class that inherits from DependencyObject and usually can be inserted in a resource dictionary in the page where it has to work. The principle of the CVS (this is the shorter name I will use from this point in advace) is acting as a filter between the source collection (IEnumerable or IList) and the component where we are showing the data. While binding a ListBox directly to a flat collection will show all the instances in the collection, putting the CVS in the middle enable us to operate on its properties to sort and filter the source.

Here is an example that shows how to embed the CVS in a xaml page; The first part show a DataSource object SampleDataCollection in the UserControl.Resources, and a CollectionViewSource that reference it using StaticResource. In the second part there is a ListBox that reference the CVS also using a StaticResource markup extension.

   1: ... omissis ...
   2:  
   3: <UserControl.Resources>
   4:     <local:DataSource x:Key="dataSource" />
   5:     <CollectionViewSource x:Name="cvs" Source="{Binding Names, Source={StaticResource dataSource}}">
   6:         <CollectionViewSource.SortDescriptions>
   7:             <scm:SortDescription Direction="Ascending" />
   8:         </CollectionViewSource.SortDescriptions>
   9:     </CollectionViewSource>
  10: </UserControl.Resources>
  11:  
  12: ... omissis ...
  13:  
  14: <ListBox ItemsSource="{Binding Source={StaticResource cvs}}" 
  15:          Margin="5,5,5,1" Grid.ColumnSpan="4" />
  16:  
  17: ... omissis ...

The magic around CVS come from an interface called ICollectionView that is esposed by the CVS in the View property. This interface represent the real working object that behind the scenes understand the source type and manage to apply filtering and sorting seamless. When a datasource is connected to the CVS a specialized instance of the ICollectionView is created - EnumerableCollectionView for IEnumerable or ListCollectionView for IList - and this instance work knowing the source data. When we connect a consumer control to the CVS it is binded directly to the ICollectionView. Watching at this interface we will see it implements INotifyCollectionChanged. This mean that if we connect the CVS to an ObservableCollection<T> all the updates to the source collection will be transmitted to the consumer.

Sorting and Filtering

Now after the basics of the CVS it is time to try to use its properties to apply the features it implements. If we see at the CVS we will see a Filter event exposed to the markup or to the code. This event is raised by the CVS every time it need to understand if an item of the collection is valid for the filter the user is appling. In the semple I included at the end of this post I use the CVS to filter a collection of italian names (strings). In the Filter event I simply compare every item in the collection to the letters the use typed in a TextBox:

   1: /// <summary>
   2: /// Handles the Filter event of the cvs control.
   3: /// </summary>
   4: /// <param name="sender">The source of the event.</param>
   5: /// <param name="e">The <see cref="System.Windows.Data.FilterEventArgs"/> instance containing the event data.</param>
   6: void cvs_Filter(object sender, FilterEventArgs e)
   7: {
   8:     e.Accepted = ((string)e.Item).ToLower().StartsWith(searchKey.Text.ToLower());
   9: }

The FilterEventArgs class expose an Accepted property useful to indicate if the element (e.Item) we are evaluating has to be shown or not. This event is very simple to handle and let the developer to apply various filtering rules. We have only to pay attention to the time that the evaluation take because it is repeated one time for every element in the collection.

While the user type in the TextBox we catch the TextChanged event and force the refresh of the CVS this way:

   1: /// <summary>
   2: /// Handles the TextChanged event of the searchKey control.
   3: /// </summary>
   4: /// <param name="sender">The source of the event.</param>
   5: /// <param name="e">The <see cref="System.Windows.Controls.TextChangedEventArgs"/> instance containing the event data.</param>
   6: private void searchKey_TextChanged(object sender, TextChangedEventArgs e)
   7: {
   8:     this.cvs.View.Refresh();
   9: }

Applying sorting if simpler than filtering. It is done by using markup with the SortDescriptions property. This property accept a collection of SortDescription, one for every property we need to sort. For each property we can choice the direction of sorting using the Direction property:

<scm:SortDescription Direction="Ascending" PropertyName="Name" />

Here is a snippet of code from the sample i provide:

   1: <CollectionViewSource x:Name="cvs">
   2:     <CollectionViewSource.SortDescriptions>
   3:         <scm:SortDescription Direction="Ascending" />
   4:     </CollectionViewSource.SortDescriptions>
   5: </CollectionViewSource>

While I'm binding strings there is no need to specify a property because the sort has to be applied directly to the source string. If you need a more complex sorting logic it is always available the IComparable interface that is used to evaluate the elements during the sort operation.

Differences from WPF

While at the first look the CollectionViewSource implementation in Silverlight appear to be very close to the WPF component, there is some subtle differences. First of all if we examine the component we may found a property called GroupDescriptions. This property is used in WPF to apply grouping but in the Silverlight version it throw a NotSupportedException. Probably it is a placeholder for future extensions of the component.

The most important difference to me if about the structure of the object. The CVS inherits from DependencyObject but while in silverlight only classes derived from FrameworkElement may be subject of DataBinding the only way to put a CVS in markup would be using a StaticResource.

This would be a huge limitation to CVS but fortunately the people from the team found a way to workaround it. Also if CVS inherits from DependencyObject it is still possible to use databinding but it is needed to specify an explicit Source like the following example:

   1: <UserControl.Resources>
   2:     <CollectionViewSource x:Name="cvs" Source="{Binding Names, Source={StaticResource dataSource}}">
   3:         <CollectionViewSource.SortDescriptions>
   4:             <scm:SortDescription Direction="Ascending" />
   5:         </CollectionViewSource.SortDescriptions>
   6:     </CollectionViewSource>
   7: </UserControl.Resources>

This is very useful if we have a complex object like a ViewModel we want to use in a page with a CVS instance. The better would be to bind directly to the datasource but is is possible to put the ViewModel in the resources and then statically reference it from both the DataContext and the CollectionViewSource.

Conclusion

Last months I decided to start writing a component like CVS because I think it is really useful in some cases. Now I'm very glad to rely on a framework component. For some of you that have been used my component take note that the CVS interface is very close to my component so it is very easy to switch to it.

Download: Elite.Silverlight3.CollectionViewSample.zip (1,04 MB)

Video: CollectionViewSource.wmv (1.08 MB)

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