Silverlight & XAML Playground
about XAML and other Amenities

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

SilverVNC - a VNC Viewer with Silverlight 4.0 RC

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

vnc

I confess I wrote the code of this example few months ago, when only Silverlight 3.0 was on the scene, and I retained it for me because it was a beautiful example but not really useful. Since it uses a socket connection it is a little bit complicated to use it in real world scenario due the fact it needs a policy server, and it is restricted to few number of ports that does not have anything to do with VNC standard ports.

Finally, when I got the first bits of Silverlight 4.0 I decided it would be time to push it out to the folks, thanks to the new out-of-browser feature that now support full-trust installation. I've been persuaded from the opportunity of have a relaxed security on Socket connections meaning that I will be able to connect to any socket based service through a well known port and without having to install a policy server.

So, here is today SilverVNC, a basic implementation of the Remote Framebuffer protocol (RFB) written following the standard specifications (you can download them from the RealVNC website). I've implemented the protocol using the most recent build of UltraVNC to make tests.

As I've already said the implementation is basic. Differently from commercial version I only support the RAW encoding and avoid any type of compression. This simply because handling heavy socket communications with the asyncronous model of silverlight is a kind of bounce game that make simple things really complicated. So I preferred to give a simple example that let the user understand how it works.

How it works?

The core of the example is made of an RfbClient class that encapsulate all the logic needed to communicate with the server, decoding data and rasing events to the user interface. The class is made of methods that receive and send data to the socket. I will not detail the inner content of the class because the RFB protocol specifications are out of the scope of this article. You have only to be aware that while in OOB-Fulltrust the socket may be opened on every port and without any policy.

The main page of the application use the RfbClient to connect to the VNC server and pump data from the socket and decode. Every time RfbClient receive something it raises two types of event:

ResizeFrameBuffer : it mean the server notified a change of the size of the screen. It usually happens at the start of the connection to let the client resize the drawing area.

FramBufferUpdate: it mean the server detected a change on the screen so it cut out a rectangle and send it to the client. The event handler calculate the position of the rectangle on the drawing area and write it.

Here is how to handle these events:

   1: void Client_ResizeFrameBuffer(object sender, EventArgs e)
   2: {
   3:     this.MakeWindowProportional(this.Client.Server.Width, this.Client.Server.Height);
   4:     this.BitMap = new WriteableBitmap(this.Client.Server.Width, this.Client.Server.Height);
   5:     this.vnc.Source = this.BitMap;
   6: }
   7:  
   8: private void MakeWindowProportional(double width, double height)
   9: {
  10:     double proportion = width / height;
  11:     Application.Current.MainWindow.Height = Application.Current.MainWindow.Width / proportion;
  12:     Application.Current.MainWindow.Activate();
  13: }
  14:  
  15: private void Client_FrameBufferUpdate(object sender, FrameBufferUpdateEventArgs e)
  16: {
  17:     Rect rect = e.Rectangle;
  18:  
  19:     int x = 0;
  20:     int y = 0;
  21:  
  22:     foreach (uint color in e.Colors)
  23:     {
  24:         this.BitMap.Pixels[
  25:             (y + (int)rect.Y) *
  26:             this.Client.Server.Width +
  27:             (x + (int)rect.X)] = (int)color;
  28:  
  29:         if (++x == rect.Width)
  30:         {
  31:             x = 0;
  32:             y++;
  33:         }
  34:     }
  35:  
  36:     this.BitMap.Invalidate();
  37: }

Future implementations

There is some improvements I think will apply in the future. First of all I think the algorithm writing into the buffer might be more efficient than the code I showed here. My idea is to implement a MediaStreamSource to produce a video stream you can connect to a MediaElement. This should be better not only from the performances point of view but also may be simpler to be used by developers which needs to add a remote desktop viewer to his applications.

Another improvement is to implement the other compression algorithms. Probably I will implement RRE, CoreRRE and Hex. Finally I would like to transform the viewer in a full functional remote desktop client adding the capability to remote control the target machine. This shouldn't be too difficult.

Until then please have a try to this sample and give me any feedback you think useful to improve it.

Source: http://www.silverlightplayground.org/assets/sources/SilverlightPlayground.RFB.zip
Video: http://www.silverlightplayground.org/assets/video/SilverVNC.wmv
RFB Specifications: The RFB Protocol

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

Using XmlDefinition and XmlPrefix to better organize namespaces

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

I'm pretty sure you agree with me if I say that namespaces in XAML are the way to the hell. I mean the intricated jungle of xml namespaces, clr namespaces and prefixes you have to handle in a medium application. Every time you add a new control in the XAML, when it come from a different namespace, Visual Studio try to guess a good name for the prefix to use in XAML tags, and obviously it goes wrong.

The problem comes from the need of having a reference to an Assembly containing the clr namespace, and probably if you use only the wysiwyg editor of blend it is not a problem if the name is long and complicated, but when you start modify the markup by hand you often found that the same namespace has a different meaning in two different files.

The RC release of Silverlight 4.0 come with a solution to this great problem. The solution has the form of two attributes, valid in assembly scope, that grant the capability of having a xml namespace defined for a give clr namespace and a default prefix to be used from the IDEs. Here is an example of how to use them:

   1: [assembly:XmlnsDefinition("http://silverlightplayground.org/xaml/controls", "SilverlightPlayground.Controls")]
   2: [assembly:XmlnsPrefix("http://silverlightplayground.org/xaml/controls", "slpgControls")]

The XmlDefinition here specify a mapping between the xml namespace (the one starting with http://) and the clr namespace SilverlightPlayground.Controls. The XmlPrefix determine that the splgControls prefix have to be used every time a reference to this namespace have to be created. Here is the result of dragging an element to the designer surface:

   1: <UserControl x:Class="SilverlightPlayground.Test.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:slpgControls="clr-namespace:SilverlightPlayground.Controls;assembly=SilverlightPlayground.Controls"  
   7:              mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400">
   8:     <Grid x:Name="LayoutRoot" Background="White">
   9:         <slpgControls:MyControl />
  10:     </Grid>
  11: </UserControl>

I don't know if this is the final solution, but I'm sure it will be important to have more organization in XAML.

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