XAML Playground
about XAML and other Amenities

Review: Mastering LOB Development for Silverlight 5: A Case Study in Action

2012-06-05T23:13:46+01:00 by codeblock

image

Braulio Diez, a friend of mine I known during the TechED 2008 in Barcelona, together with other authors has recently written a book about Silverlight 5. The "Mastering LOB Development for Silverlight 5: A Case Study in Action", published by PackLib is an interesting book that is able to point the light on the Silverlight topic, mixing together a good scan about Silverlight 5.0 features and a number of "cases study" that focus the attention of the reader on the power of this, still unmatched and irreplaceable, piece of technology.

In a time that seems to be pointed to the most new evolutions, inside the new version of Windows, mostly directly derived from Silverlight, reading this book may be a useful exercise to understand what it can do and what someone can still do using XAML instead of HTML5.

My thanks to Braulio for the pleasant reading.

http://www.packtpub.com/mastering-lob-development-silverlight-5/book

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

Metro: Implement a parallactic scrolling for your GridView

2012-05-19T00:56:36+01:00 by codeblock

A customer of mine asked me about how to create a "parallactic scrolling" for the background of a GridView. For people that do not know what it is, parallactic scrolling is when you have a background image scrolling slower than the foreground content. This tecnique is mostly used in games to give the impression of depth of field with the overlapping of a number of elements that moves slower when they apper to be far from the observer.

To have a good example of this beautiful effect you can try the music hub of your Windows Phone. The Panorama based scrolling, when coupled with a background image, automatically apply a parallactic effect when you move from a panel to the following.

Coming to Windows 8, there are some application installed by default that shows a similar effect. Weather and Finacial apps shows a partial parallactic effect when transitionig between the start screen and the right content. GridView, ScrollViewer and other controls does not automatically apply this effect (almost not in windows 8 CP), but a simple trick let you easily show the effect in your apps.

First of all you have to produce an element, that is greater than the viewport in the direction you desire your scrolling to work. In the application of my user group it is an image made of people an the total size is almost double of the medium size of a screen device. This image is aligned to left and goes out of the screen on the right. Here is the code:

   1: <Grid>
   2:     <Image x:Name="backImage" Margin="0,0,0,30" 
   3:             HorizontalAlignment="Left" VerticalAlignment="Bottom" 
   4:             Source="/Assets/parallax_people.png" Width="2250" Height="200" Opacity="0.5" />
   5:  
   6:     <ScrollViewer x:Name="hScroll" 
   7:                   Style="{StaticResource HorizontalScrollViewerStyle}" Margin="0">
   8:         <!-- insert your content here -->
   9:     </ScrollViewer>
  10: </Grid>

The trick I'm showing works only with ScrollViewer because it requires to handle the ViewChanged event, but you can for sure include a GridView into a ScrollViewer and have the effect enabled for the control. And obviously this also apply to ListView as well.

Now, going to codebehind is is required to subscribe the ViewChanged event. This event is raised every time the user scrolls the content. So I have to recalculate the offset of the background using the HorizontalOffset property and to map the value to the total width of the image. Here is the code:

   1: private void hScroll_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
   2: {
   3:     var delta = (this.hScroll.HorizontalOffset / this.hScroll.ScrollableWidth) * (backImage.ActualWidth - this.hScroll.ViewportWidth);
   4:     this.backImage.Margin = new Thickness(-delta, 0, 0, 30);
   5: }

Once you have connected the method to the View the trick is done. In this code I use the Margin property to move the image. At the first sight you would have used a TranslationTranform. Unfortunately the Render tranforms clips the image so I finally adopted the Margin property with a negative value.

In my example you can tune the speed of the content  varying the width of the background image, but nothing else is required.

Metro: A simple class to handle retry on network calls

2012-05-18T00:31:23+01:00 by codeblock

After you start working with metro-style applications, you may be concerned by the extensively adopted asyncronous model. If you ever used Silverlight you can be aware that this model comes directly as an inheritance from it. In metro-style applications this model is taken to the extreme consequences. As an example WinRT exposes all the operations that takes longer than 50ms with an asyncronous pattern. But the most frequent case where you meet asynchronicity, is when you call the network.

The use of Task Parallel Library offers anumber of interesting opportunities to handle asynchronous operations and the benefits can make your code most simple and reusable. Recently I've created an interesting class (I called it NetworkCallManager). This class wraps every network call and let you control the flow of a call in the case it returns an error. It is common to handle timeouts, authentication issues and poor network connectivity and if you read the guidelines you know that they suggests you to let the user retry the failed operation. Here is the code I wrote:

   1: public class NetworkCallManager
   2: {
   3:     public event EventHandler<NetworkErrorEventArgs> NetworkError;
   4:  
   5:     protected virtual void OnNetworkError(NetworkErrorEventArgs args)
   6:     {
   7:         EventHandler<NetworkErrorEventArgs> handler = this.NetworkError;
   8:  
   9:         if (handler != null)
  10:             handler(this, args);
  11:     }
  12:  
  13:     public async Task<T> Execute<T>(Func<Task<T>> task)
  14:     {
  15:         bool retry = false;
  16:  
  17:         do
  18:         {
  19:             Exception error = null;
  20:  
  21:             try
  22:             {
  23:                 return await task();
  24:             }
  25:             catch (Exception ex)
  26:             {
  27:                 error = ex;
  28:             }
  29:  
  30:             if (error != null)
  31:             {
  32:                 NetworkErrorEventArgs args = new NetworkErrorEventArgs(error);
  33:                 this.OnNetworkError(args);
  34:                 retry = !args.Cancel;
  35:             }
  36:  
  37:         } while (retry);
  38:  
  39:         throw new NetworkOperationCancelledException("Network operation has been cancelled");
  40:     }
  41: }

The main method, responsible to place the network call, is named Execute. It receives a Task<T> where T is compatible with the return type of the network call we have to execute. The important thing to understand is that you have tu use a lambda expression because the code inside the method can recall this function lot of times. The method works as a pass-through function since it returns the same type as the function passed. So when the task is completed you can get directly the result.

Inside the body the method starts a loop where it runs the task and handles exceptions. When an exception is raised it gracefully handle the error and notifies it to the caller. The user can choose to break the operation or to retry. Here is how you can use the class:

   1: // omissis
   2:  
   3: NetworkCallManager ncm = new NetworkCallManager();
   4: ncm.NetworkError += HandleNetworkError;
   5:  
   6: try
   7: {
   8:     this.Speeches = await ncm.Execute<IEnumerable<SpeechDTO>>(() => this.DataService.GetSpeechesInYears(5));
   9: }
  10: catch (NetworkOperationCancelledException ex)
  11: {
  12:     // swallow
  13: }
  14: catch (Exception ex)
  15: {
  16:     this.DialogService.ShowGenericError(ex.Message);
  17: }
  18: finally
  19: {
  20:     ncm.NetworkError -= HandleNetworkError;
  21: }
  22:  
  23: private async void HandleNetworkError(object sender, NetworkErrorEventArgs e)
  24: {
  25:     e.Cancel = await this.DialogService.ShowNetworkError(e.Error);
  26: }
  27:  
  28: // omissis

This pattern let you to use the wrapper in a trasparent way and directy get the result. It also raises a specific exception when the user choose to stop the operation instead of retry. To me this spered me to implemend this flow directly into the page.

Implement a NavigationService for MVVM in Metro Applications

2012-05-10T00:37:56+01:00 by codeblock

When you write a Metro-style app using the MVVM pattern, you are requested to abstract navigation for the pattern purposes. The problem comes from having navigation methods (Navigate, GoBack, etc...) available only in the View via the Frame control and navigate from the ViewModel may be an hard task.

During the development of my last metro app for my user group, I found a stylish way of creating a NavigationService to be injected in ViewModels. The trick is to create a NavigationService class and let it create and initialize the RootFrame and inject it into the Window.Current.Content.

   1: public class NavigationService : INavigationService
   2: {
   3:     protected Frame RootFrame { get; private set; }
   4:  
   5:     public NavigationService()
   6:     {
   7:         this.RootFrame = new Frame();
   8:     }
   9:  
  10:     public void Initialize(Window window, bool activate = true)
  11:     {
  12:         if (window.Content == null)
  13:             window.Content = this.RootFrame;
  14:  
  15:         if (activate)
  16:             window.Activate();
  17:     }
  18:  
  19:     public virtual void Navigate(Type destination, object parameter = null)
  20:     {
  21:         // avoid navigation if current equals to destination
  22:  
  23:         if (this.RootFrame.CurrentSourcePageType != destination)
  24:             this.RootFrame.Navigate(pageType, parameter);
  25:     }
  26:  
  27:     public virtual void GoBack()
  28:     {
  29:         if (this.RootFrame.CanGoBack)
  30:             this.RootFrame.GoBack();
  31:     }
  32:     
  33:     public virtual void GoForward()
  34:     {
  35:         if (this.RootFrame.CanGoForward)
  36:             this.RootFrame.GoForward();
  37:     }
  38:     
  39:     public virtual bool CanGoBack
  40:     {
  41:         get { return this.RootFrame.CanGoBack; }
  42:     }
  43:     
  44:     public virtual bool CanGoForward
  45:     {
  46:         get { return this.RootFrame.CanGoForward; }
  47:     }
  48:     
  49:     public virtual void Save()
  50:     {
  51:         throw new NotImplementedException();
  52:     }
  53:     
  54:     public virtual void Load()
  55:     {
  56:         throw new NotImplementedException();
  57:     } 
  58: }

The previous box shows the code of my service: first of all the service implements an interface. This serves for the dependency injection since ViewModel only accept INavigationService to make it testable. The Initialize method sets the Window.Content to the frame instance I created in the constructor. Finally the class implements all the required navigation methods. Interesting to say, you can implement Save and Load using Framee.GetNavigationStatus and Frame.SetNavigationStatus to persist the navigation backstack when your app is terminated. Here is how to use the class in the App.xaml.cs:

   1: protected override void OnLaunched(LaunchActivatedEventArgs args)
   2: {
   3:     // get the instance from Injection Container
   4:     INavigationService ns = this.Container.Resolve<INavigationService>();
   5:  
   6:     if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
   7:     {
   8:         // load state if app was terminated
   9:         ns.Load();
  10:     }
  11:     
  12:     // initialize current window
  13:     ns.Initialize(Window.Current);
  14:  
  15:     // navigate to the first page
  16:     ns.Navigate(Pages.MainPageType);
  17: }
  18:  
  19: private void OnSuspending(object sender, SuspendingEventArgs e)
  20: {
  21:     // get the instance from Injection Container
  22:     INavigationService ns = this.Container.Resolve<INavigationService>();
  23:  
  24:     // save navigation status
  25:     ns.Save();
  26: }

This code shows also how to load and save to persistence media the navigation history. In this way when you return to the app after it has been terminated, it can reload again an exact navigation.

Metro: Wire events to ICommand with a (not so simple) extension

2012-04-10T00:58:49+01:00 by codeblock

Looking to the new Metro style applications in Windows 8, I recently found that the easiness of Silverlight lost some points in the move to the new Metro application environment. One of the important things that are missed in XAML for Metro is the ability of wire events of the View to commands in the ViewModel. To be more precise, this capability exists but is limited to instances of ButtonBase class like Button and Hyperlinks. This scenario is known to Silverlight developers but it is easy worked around with Behaviors. Behaviors and Triggers comes from the Expression Blend SDK and are very useful. I think many of you know the EventToCommand class provided by the MVVM Light Toolkit that is able to wire commands to every kind of events.

Unfortunately behaviors are not supported in Metro applications (at least for the moment) so the sole way to handle events is to use codebehind to programmatically call commands of the ViewModel. For this reason I started to work hard to find a way to create a behavior's surrogate, and I finally achieved this result. Please take note that the solution I present here relies on two tricks made to work around some limitations I found. I hope these workarounds will not be required anymore in the future.

Create an infrastructure

As many know, Behaviors are based on Attached Properties. This useful feature still exists in XAML for Metro so it seems possible to replicate the behaviors writing some code. For the purpose of my goal, fully recreate the behaviors infrastructure is too difficult and takes too much time. So I decided to work striping out every kind of generalization and go straight to the minimal implementation.

In the solution attached to this post there are 6 classes that supports the behavior-style:

AttachableCollection: a special collection that can be attached to a DependencyObject. This instance is the element to which the binding is attached (an element of the Visual Tree)

DependencyObjectCollection: a generic collection able to host dependency objects. This collection is a DependencyObject itself.

Command: this class represents the binding of an event to a command. It is able to receive the name of the event, the binding to the command an to the command parameter. All the logic to connect the event to the command is hosted inside this class and its inner classes.

CommandCollection: AttachableCollection that contains the commands related to a single element of the visual tree

IAttachedObject: interface implemented by AttachableCollection and Command. It allows to connect the element source of events to the classes partecipating to the structure.

Extensions: static class used to expose the Attached Property

Thanks to these classes you will be able to write the following XAML:

   1: <Button Content="{Binding ButtonTitle}">
   2:     <xpg:Extensions.Commands>
   3:         <xpg:Command EventName="Click" Binding="{Binding ClickCommand}" ParameterBinding="{Binding ButtonTitle}" />
   4:         <xpg:Command EventName="Holding" Binding="{Binding HoldCommand}" ParameterBinding="{Binding ButtonTitle}" />
   5:     </xpg:Extensions.Commands>
   6: </Button>

Fully explaining the solution is hard. I invite you to explore the source codes I provide to understant the reasons behind every single class. The only thing you must have clear in mind is that most of the classes are made to propagate the instance of the source object along all the commands instances.

How it works

Part of the solution I've created starts from this post in codeproject. It describes a solution, based on attached properties, that enable to connect a single event to a command. Unfortunately this solution works only with the previous Developer Preview but it does not works with the latest Windows 8 Community Preview.

The reason is hard to understant to me, but it seems something in WinRT prevents to programmatically attach events. The following code results in an exception:

   1: if (eventInfo != null)
   2: {
   3:     Delegate handler = eventHooker.GetEventHandler(eventInfo);
   4:     eventInfo.AddEventHandler(d, handler);
   5: }

To work around to this problem I found a new class that seems to be created for this exact purpose. The class WindowsRuntimeMarshal contains a method named AddEventHandler that does the same. The documentation states this class is created to support the .NET Framework. But it is the only way to hook events as we need.

   1: if (eventInfo != null)
   2: {
   3:      Delegate handler = eventHooker.GetEventHandler(eventInfo);
   4:  
   5:      WindowsRuntimeMarshal.AddEventHandler<Delegate>(
   6:          dlg => (EventRegistrationToken)eventInfo.AddMethod.Invoke(dependencyObject, new object[] { dlg }),
   7:          etr => eventInfo.RemoveMethod.Invoke(dependencyObject, new object[] { etr }), handler);
   8: }

After this the events are hooked up and the command need to be raised. This presents another problem. No matter if the base class is DependencyObject or FrameworkElement, there is not any way to get databinding to work as I expect. I need to deep investigate on this problem but for the moment I was able to get the Binding object and to evaluate it using a BindingEvaluator class. This is the main reason because I've not user Command and CommandParameter for the properties but instead I used Binding and ParameterBinding. Here is the code to read databinding:

   1: /// ... omissis
   2:  
   3: private void OnEventRaised(object sender, object e)
   4: {
   5:      BindingEvaluator commandBinding = new BindingEvaluator((FrameworkElement)sender, this.Binding.Binding);
   6:      ICommand command = commandBinding.Value as ICommand;
   7:  
   8:      object commandParameter;
   9:  
  10:      if (this.Binding.ParameterBinding is Binding)
  11:      {
  12:          BindingEvaluator commandParameterBinding = new BindingEvaluator((FrameworkElement)sender, (Binding)this.Binding.ParameterBinding);
  13:          commandParameter = commandParameterBinding.Value;
  14:      }
  15:      else
  16:          commandParameter = this.Binding.Parameter;
  17:  
  18:      if (command != null)
  19:          command.Execute(commandParameter);
  20: }
  21:  
  22: /// ... omissis
  23:  
  24: private sealed class BindingEvaluator : FrameworkElement
  25: {
  26:     /// <summary>
  27:     /// Instance of the binding to evaluate
  28:     /// </summary>
  29:     private Binding Binding { get; set; }
  30:  
  31:     #region Value
  32:  
  33:     /// <summary>
  34:     /// Exposes the Dependency Property related to the Value property
  35:     /// </summary>
  36:     public static readonly DependencyProperty ValueProperty =
  37:         DependencyProperty.Register("Value", typeof(object), typeof(BindingEvaluator), new PropertyMetadata(DependencyProperty.UnsetValue));
  38:  
  39:     /// <summary>
  40:     /// Gests the value retrieved from the binding
  41:     /// </summary>
  42:     public object Value
  43:     {
  44:         get
  45:         {
  46:             return (object)GetValue(ValueProperty);
  47:         }
  48:         private set { SetValue(ValueProperty, value); }
  49:     }
  50:  
  51:     #endregion
  52:  
  53:     /// <summary>
  54:     /// Create an instance of the evaluator
  55:     /// </summary>
  56:     /// <param name="element">Instance of element to inherit data context</param>
  57:     /// <param name="binding">Instance of the binding to evaluate</param>
  58:     public BindingEvaluator(FrameworkElement element, Binding binding)
  59:     {
  60:         this.DataContext = element.DataContext;
  61:         this.Binding = binding;
  62:         SetBinding(BindingEvaluator.ValueProperty, this.Binding);
  63:     }
  64: } 
  65:  

Conclusion

With these workarounds the solution now works. I'm using it in a project I'm working to develop usign MVVM Light Toolkit. It allows to easily connect Views to ViewModels without wasting codebehind with lot of event handlers. If you want I attached the code, side by side with an example. Please feel free to contact me for any issue or suggestion.

Download: http://www.silverlightplayground.org/assets/sources/XPG.Extensions.zip (396kb)

Download Silverlight & WP7 RFB Library

2012-03-07T00:34:58+01:00 by codeblock

Senza-titolo-1Today I decided to release the libraries I wrote to handle the VNC connection, implementing the Remote Framebuffer protocol, as an Open Source project under the Creative Common license. You can download the library from this page:

http://xamlplayground.org/page/Silverlight-WP7-RFB.aspx

During last weeks I've published a new version of SilverVNC, my popular client for Remote Framebuffer connections, that works on Windows Phone 7.5. After publishing the software as Open Source project on codeplex, for Silverlight 3.0 only, now the marketplace has also a mobile version that you can download for free or buy at these addresses:

Free Edition: view only
http://www.windowsphone.com/it-IT/apps/ef2ef5b9-192c-4d77-a684-c1e69bea24fa

Standard Edition: full control
http://www.windowsphone.com/it-IT/apps/e6c631e6-f6c4-49e5-98a9-d49eea8212cf

Enjoy the library.

Take a screenshot with Silverlight 5.0 and pInvoke

2012-02-28T00:36:14+01:00 by codeblock

PInvoke is a new entry in Silverlight 5.0 runtime. For the one that are not aware of what is pInvoke I will say it stands for "Platform Invoke". It is a set of classess and attributes that allows the Silverlight runtime to access the low-level Win32 API of Windows Operating System.

After Silverlight 4.0 brought COM interop in Silverlight, the team decided to accomplish the last step and integrate also pInvoke. As you understand, it is only restricted to Windows OS, but is some scenario it may be a very useful thing to cross the subtle line from "can't do" to "can do". Wether you have to detect USB keys, interact with devices and so on, pInvoke require you to directly access the API preparing the mapping to the OS funzions and handling unmanaged resources.

As a littel sample I ported an old example to Silverlight. The code below implements a simple funzion that is able to take a screenshot of the desktop.

   1: public static class ScreenCapture
   2: {       
   3:   public static WriteableBitmap GetDesktopImage()
   4:   {
   5:       WriteableBitmap bmap = null;
   6:  
   7:       // initialize unmanager pointers
   8:       IntPtr hDC = IntPtr.Zero,
   9:              hMemDC = IntPtr.Zero,
  10:              desktop = IntPtr.Zero;
  11:  
  12:       try
  13:       {
  14:           // get a reference to desktop
  15:           desktop = User32.GetDesktopWindow();
  16:           // get an handle to Device Context
  17:           hDC = User32.GetDC(desktop);
  18:           // create a new Device Context in memory
  19:           hMemDC = Gdi32.CreateCompatibleDC(hDC);
  20:  
  21:           // read size of desktop window
  22:           Size size = new Size
  23:           {
  24:               Width = User32.GetSystemMetrics(Gdi32.SM_CXSCREEN),
  25:               Height = User32.GetSystemMetrics(Gdi32.SM_CYSCREEN)
  26:           };
  27:  
  28:           // create a bitmap compatible with desktop
  29:           IntPtr hBitmap = Gdi32.CreateCompatibleBitmap(hDC, size.Width, size.Height);
  30:  
  31:           if (hBitmap != IntPtr.Zero)
  32:           {
  33:               // select memory Device Context into the new bitmap
  34:               IntPtr hOld = (IntPtr)Gdi32.SelectObject(hMemDC, hBitmap);
  35:  
  36:               // copy the desktop to the memory handle
  37:               Gdi32.BitBlt(hMemDC, 0, 0, size.Width, size.Height, hDC, 0, 0, (int)TernaryRasterOperations.SRCCOPY);
  38:  
  39:               // select the memory Device Context into the bitmap
  40:               Gdi32.SelectObject(hMemDC, hOld);
  41:  
  42:               // initialize a bitmap info
  43:               BitmapInfo bi = new BitmapInfo 
  44:               { 
  45:                   biSize = Marshal.SizeOf(typeof (BitmapInfo)), 
  46:                   biWidth = size.Width, 
  47:                   biHeight = size.Height, 
  48:                   biPlanes = 1, 
  49:                   biBitCount = 32, 
  50:                   biCompression = 0, 
  51:                   biSizeImage = 0, 
  52:                   biXPelsPerMeter = 0, 
  53:                   biYPelsPerMeter = 0, 
  54:                   biClrUsed = 0, 
  55:                   biClrImportant = 0 
  56:               };
  57:  
  58:               // calculate byte size of the area
  59:               int dwBmpSize = ((size.Width * bi.biBitCount + 31) / 32) * 4 * size.Height;
  60:               byte[] data = new byte[dwBmpSize];
  61:  
  62:               // initialize a WriteableBitmap to output the result
  63:               bmap = new WriteableBitmap(size.Width, size.Height);
  64:  
  65:               // copy bitmap to byte array
  66:               Gdi32.GetDIBits(hMemDC, hBitmap, 0, (uint)size.Height, data, ref bi, 0);
  67:  
  68:               // compy byte array to WriteableBitmap
  69:               for (int i = 0; i < data.Length; i += 4)
  70:               {
  71:                   int y = size.Height - ((i / 4) / size.Width) - 1;
  72:                   int x = (i / 4) % size.Width;
  73:                   int pixel = data[i + 0] | (data[i + 1] << 8) | (data[i + 2] << 16) | (data[i + 3] << 24);
  74:                   bmap.Pixels[y * size.Width + x] = pixel;
  75:               }
  76:           }
  77:       }
  78:       finally
  79:       {
  80:           // release unmanaged resources
  81:           if (hMemDC != IntPtr.Zero)
  82:               Gdi32.DeleteDC(hMemDC);
  83:           if (hDC != IntPtr.Zero)
  84:               User32.ReleaseDC(desktop, hDC);
  85:       }
  86:  
  87:       // return bitmap
  88:       return bmap;
  89:   }
  90: }

I wrote a number of comments inside the code example to try explain how it works, but in a few words it create a buffer in memory, take a reference to the desktop and copies it to the new area. Then finally it copy again the buffer to a byte array to allow managed code to access the captured image. It is copied to a WriteableBitmap and then returned to the caller.

To use the class you can simply call the static method and check for the result value and exceptions. The code automatically handles the unmanaged resources and is done to freed them before to exit.

   1: private void Button_Click(object sender, RoutedEventArgs e)
   2: {
   3:     Application.Current.MainWindow.Hide();
   4:  
   5:     Delay(1000,
   6:           () =>
   7:           {
   8:               try
   9:               {
  10:                   BitmapSource source = ScreenCapture.GetDesktopImage();
  11:  
  12:                   if (source != null)
  13:                       screenshot.Source = source;
  14:                   else
  15:                       MessageBox.Show("Impossibile completare la cattura!");
  16:               }
  17:               catch (Exception ex)
  18:               {
  19:                   MessageBox.Show(ex.Message);
  20:               }
  21:               finally
  22:               {
  23:                   Application.Current.MainWindow.Show();
  24:                   Application.Current.MainWindow.Activate();
  25:               }
  26:           });
  27: }
  28:  
  29: private void Delay(int timeout, Action action)
  30: {
  31:     Task task = new Task(
  32:         () =>
  33:         {
  34:             Thread.Sleep(timeout);
  35:  
  36:             Deployment.Current.Dispatcher.BeginInvoke(action);
  37:         });
  38:  
  39:     task.Start();
  40: }

This code minimizes the main window and then take a screenshot. Finally it reactivate the window and take it to the front. To compile this code you have to import a number of structures. The attached sample includes all the needed classes.

Download: XPG.PInvoke.zip

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

Reliable themes: Plan for fonts

2012-02-24T00:12:56+01:00 by codeblock

After you completes the first steps in creating your reliable theme, it is now time to move forward and consider another aspect in this task. When the palette is ready the next step in to plan for the typefaces. Fonts are a crucial aspect tha shares with colors the scene almost with the same weight.

Choosing the wrong typeface means make your application difficult to read so the user can be tired after a short usage, but this is only one aspect of the problem. Togheter with colors, fonts contribute to the general feel about the reliability and effectiveness of the user interface. It is really important to carefully choose a wide set of options about fonts

aspect of the typeface: it exists a huge number of typefaces and every one of them can be used in specific context. Carefully evaluate your font, preferring sans-serif on serif because the first one are more readable in different sizes when used in user interfaces.

size of the font: size matters, and it is not a joke. Size is not only a problem of readability but also a problem of space. you have to choose the right size balancing the readability and the space available for your content. Also you have to consider that big does not means automatically easy to read. Using an huge typeface can significantly reduce the number of words you can write in a row and force the user to move from left to right too much times.

significance and uniformity of the size: the size is also a problem of meaning. Using a big font makes the content really preminent over another part where you use a smaller typeface. An also you have to use an omogeneous size across different parts of the application. As an example if you decide to use a given size for the grid header you have to use the same size on all the grids of the application.

careful use font weight: font weight and italic can give an additional gear to your interface but as usual, abusing in bold and italics can make the interface confused and not readable. For this topic it is valid the same rule of the previous point. Choose a weight and style for each meaning and the use it omogeneously across all the elements.

contrast of font on background: color of the typeface can affect readability more than size. Always use an high contrast between the foreground and background but not the maximum. Using too high contrast can create flickering effect and reduce readability.

After choosing typeface, size, weight and the other parameters I discussed in the previous paragraphs, it is time to embed them in your theme. Here is a short set of easy rules:

#1 - Plan the fonts matrix

Given that you only use a unique typeface for your application, or that you plan for a single typeface at a time, the font used in your theme can be easily organized using a matrix. Your fonts matrix have the weight in the rows and the sizes in the columns. Here is a simple matrix:

  10pt 12pt 14pt 18pt 24pt 32pt 48pt
light
           
semilight side notes            
normal   textbox content   grid headers      
semibold       titles    
bold   input labels          
 

The font matrix really can help to better understand fonts across the parts of your application. You know that the upper left corner identifies parts that are less important than the lower bottom cell. You do not have to fill every cell in the matrix, but on the contrary the better is leaving the most of the cells empty.

#2 - Name your weights and sizes

Then, as we have done with colors, it is important to abstract names for weights and sizes. Primarily for sizes but also for weights you have to use a naming convention that remove the need of knowing the number or the real weight of the typeface. For weights you can user terms like "Light", "SemiLight", "Normal", "SemiBold", "Bold". You can alternatively use FontWeight or FontFace to determine weight. Lot of fonts are created in various flavors with a face for every weight. Segoe UI is an example.

   1: <FontFamily x:Key="FontFamilyLight">Segoe UI Light</FontFamily>
   2: <FontFamily x:Key="FontFamilySemiLight">Segoe UI SemiLight</FontFamily>
   3: <FontFamily x:Key="FontFamilyNormal">Segoe UI</FontFamily>
   4: <FontFamily x:Key="FontFamilySemiBold">Segoe UI SemiBold</FontFamily>
   5: <FontFamily x:Key="FontFamilyBold">Segoe UI Bold</FontFamily>

For sizes I usually use "ExtraSmall", "Small", "Normal", "Medium", "Large", "ExtraLarge", etc... This naming helps to separate the real size from the meaning of the size. You can assign to Normal a size of 12 or 18 and then recalculate all the other sizes on the base of the middle value. It is not important the regularity of the distribution but most of the times the distance between the intervals increase on the growing of the size.

   1: <mscor:Double x:Key="FontSizeTiny">9.33</mscor:Double>
   2: <mscor:Double x:Key="FontSizeExtraExtraSmall">10.667</mscor:Double>
   3: <mscor:Double x:Key="FontSizeExtraSmall">12</mscor:Double>
   4: <mscor:Double x:Key="FontSizeSmall">13.333</mscor:Double>
   5: <mscor:Double x:Key="FontSizeNormal">14.667</mscor:Double>
   6: <mscor:Double x:Key="FontSizeMedium">18.667</mscor:Double>
   7: <mscor:Double x:Key="FontSizeMediumLarge">21.333</mscor:Double>
   8: <mscor:Double x:Key="FontSizeLarge">24</mscor:Double>
   9: <mscor:Double x:Key="FontSizeExtraLarge">29.333</mscor:Double>
  10: <mscor:Double x:Key="FontSizeExtraExtraLarge">37.333</mscor:Double>
  11: <mscor:Double x:Key="FontSizeHuge">42.667</mscor:Double>

Remember that if you decide to use FontWeight for name the weight of the your application you have then to name your face:

   1: <!-- WEIGHTS -->
   2: <FontWeight x:Key="FontWeightLight">Thin</FontWeight>
   3: <FontWeight x:Key="FontWeightSemiLight">Light</FontWeight>
   4: <FontWeight x:Key="FontWeightNormal">Normal</FontWeight>
   5: <FontWeight x:Key="FontWeightSemiBold">Bold</FontWeight>
   6: <FontWeight x:Key="FontWeightBold">Black</FontWeight>
   7:  
   8: <!-- FACE -->
   9: <FontFamily x:Key="FontFamilyDefault">Segoe UI</FontFamily>

#3 - Name your styles

As you should never use your colors directly in the markup, you should never use font family, weight and size in the same way. For fonts the problem is slightly more complicated because there is not a "Brush" instance to define to wrap the typeface. You have then to define a style for every control that have to use the typeface.

This may seems difficult but you have to keep in mind that, soon or later you will have to create a style for each element you have to put in the markup. So it is normal to assign the right typeface, weight and size combination to each one.

The most obvious element you have to create a style is TextBlock. And for textblocks you can use a conventional naming that identifies the parts where you have to put the text. To be more clear, the style you apply to textblock is the one you wrote in the cell of the font matrix.

<Style x:Key="TextInputLabelStyle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="{StaticResource FontFamilyBold}" />
<Setter Property="FontSize" Value="{StaticResource FontSizeNormal}" />
</Style>


Also remember to determine the default aspect of the TextBlock using implicit styles

<Style TargetType="TextBlock" BasedOn="{StaticResource TextInputLabelStyle}" />

After this your fonts have been strongly organized in your theme and you can start using blend to edit styles and templates. Blend UI is able to show your planned fonts easily and you can take advantage of naming to make the look & feel more effective.

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

Draw your Paths with Logo Turtle Graphics

2012-02-20T22:58:55+01:00 by codeblock

Working on a presentation I'm preparing about Silverlight 5.0, I wrote a funny example to demonstrate the new "Vector Printing" feature. My purpose was to put together a bunch of lines to send to the printer, but I was unsatisfied by any result I created by hand.

So, all of a sudden, I remembered the beauty of some figures, I drawed long time ago (perhaps I was 15), using the Logo Turtle Graphics principles and decided to write some code to draw them again. The result is funny. Try yourself to move the sliders in the following application to see the figures.

The code behind the example is really simple. I wrote a basic Turtle class that is able to manage the position of the turtle. It exposes a basic set of methods that emulates the movements that are tipical of a Logo procedure. Forward, Backward, Left and Right and so on.

   1: public class Turtle
   2: {
   3:     // Collection of geometries to draw the figure
   4:     private GeometryGroup Geometries { get; set; }
   5:     // current angle of the turtle
   6:     public double Angle { get; private set; }
   7:     // current position of the turtle
   8:     public Point Position { get; private set; }
   9:     // position of the pen
  10:     public bool IsPenDown { get; private set; }
  11:  
  12:     /// <summary>
  13:     /// Inizializza una nuova istanza della classe <see cref="Turtle"/>.
  14:     /// </summary>
  15:     public Turtle(Path path)
  16:     {
  17:         this.Geometries = new GeometryGroup();
  18:         path.Data = this.Geometries;
  19:         this.Angle = 0.0;
  20:         this.Position = new Point(0, 0);
  21:         this.IsPenDown = true;
  22:     }
  23:  
  24:     // lift up the pen
  25:     public void PenUp()
  26:     {
  27:         this.IsPenDown = false;
  28:     }
  29:  
  30:     // lower the pen
  31:     public void PenDown()
  32:     {
  33:         this.IsPenDown = true;
  34:     }
  35:  
  36:     // move forward
  37:     public void Forward(double size)
  38:     {
  39:         this.Move(size);
  40:     }
  41:  
  42:     //  move backward
  43:     public void Backward(double size)
  44:     {
  45:         this.Move(-size);
  46:     }
  47:  
  48:     // rotate to the left
  49:     public void Left(double angle)
  50:     {
  51:         this.Angle += ToRadians(angle);
  52:     }
  53:  
  54:     // rotate to the right
  55:     public void Right(double angle)
  56:     {
  57:         this.Angle -= ToRadians(angle);
  58:     }
  59:  
  60:     // move the pen of the specified size
  61:     private void Move(double size)
  62:     {
  63:         Point past = this.Position;
  64:  
  65:         this.Position =
  66:             new Point(
  67:                 past.X + Math.Sin(this.Angle) * size,
  68:                 past.Y + Math.Cos(this.Angle) * size);
  69:  
  70:         if (IsPenDown)
  71:         {
  72:             this.Geometries.Children.Add(
  73:                 new LineGeometry
  74:                 {
  75:                     StartPoint = past,
  76:                     EndPoint = this.Position,
  77:                 });
  78:         }
  79:     }
  80:  
  81:     // convert degrees to radians
  82:     public double ToRadians(double angle)
  83:     {
  84:         return angle * Math.PI / 180.0;
  85:     }
  86: }

Then a short C# function does the rest and draws the figure on the basis of a simple mathematical algorithm. It simply repeat a poligon a number of times, rotating the origin point of a short amount of degrees. The sliders change the number of sides of the poligon and the amount of the rotation expressed in fraction of 360°.

   1: private void Draw(Path pathToDraw)
   2: {
   3:     int sides = (int)this.SidesSlider.Value;
   4:     double corner = 360 / (double)sides;
   5:     int repeat = (int)this.RepeatSlider.Value;
   6:     double angle = 360 / (double)repeat;
   7:  
   8:     Turtle turtle = new Turtle(pathToDraw);
   9:  
  10:     for (int j = 0; j < repeat; j++)
  11:     {
  12:         for (int i = 0; i < sides; i++)
  13:         {
  14:             turtle.Forward(50);
  15:             turtle.Left(corner);
  16:         }
  17:  
  18:         turtle.Right(angle);
  19:     }
  20: }

I'm always impressed by the beauty of the simple mathematical drawing. The prints I got from this example have been forwarded to my daughter and some hours after they are completely coloured and becomed a beautiful picture for the door of our refrigerator. I hope you like this funny Vector Printing example.

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

Reliable Themes: Plan for colors

2012-02-17T00:59:44+01:00 by codeblock

Working on applications built with Silverlight, it is really common you have to deal with styles, templates, and often this means you have to build a theme pervading an entire application. Building a theme is not so simple as you may believe at the first sight. It requires instead a careful planning, from the conceptual side first and in the technical implementation then. There are lot of topics regarding the creation of a theme from the designer point of view but here I want to discuss about the implementation details that are often underestimated.

Styles are a great thing. But if you ever tried to use them without a careful planning you are aware that, more than often, they become a nightmare. We all are conscious about the reasons that move us to adopt styles in an application, but when the time comes we all tent to forget these reasons. And this is the mother of all the mistakes - ok, not only about styles - that usually makes our "stylesheet" more similar to a disordered trashcan instead of an useful thing. You start coding UI, then you understand that some properties have the same values, so you extract them and put it into a style. This may seems good but soon (or perhaps too late) you start to be unable to reuse the same style on more than two or three controls before you need to duplicate it.

Planning for styles is a difficult game, but it may change your life to the better if you know where to start from. And in my humble opinion the real start point - just after the end of the designer's work - is to create a palette. Colors and Brushes are usually the most obvious properties you move to a style, but having your colors spread over a 5 thousand rows stylesheet is almost not useful as if it was spread along all the pages. So, before you start, write down this sentence and put it on top of your monitor: "I will never write a color manually more than once".

#1 - Name your colors

It may seems silly but this rule automatically imply we have to name our colors. Ok guy, please stop writing now. Do not name Red as Red. Instead you have to use a more meaningful naming that adhere to the matter of your application. I usually make large use of adjectives like "Light" and "Dark". The reason to not name Red as Red (this is about to become another sentence to put on your monitor) it that easily, what it is Red now may become Green tomorrow and you for sure do not want to name as Red all your Green :) If a theme make its work fine it allows you to easily change lot of your UI without changing anything in the pages. So, here is a simple example of a named palette:

   1: <Color x:Key="ExtraDarkColor">#FF333333</Color>
   2: <Color x:Key="DarkColor">#FF666666</Color>
   3: <Color x:Key="BasicColor">#FF888888</Color>
   4: <Color x:Key="LightColor">#FFdddddd</Color>
   5: <Color x:Key="ExtraLightColor">#FFeeeeee</Color>

This is a very simple example but it explains the point effectively. You have to choose your names basing more on where or when they are used instead of the color they represent. It is a good rule of thumb to have a scale of light fore each color you use in your palette. This makes your life easy when you need to present selections, embossed borders (really? please avoid emboss your borders) and so on. This section has to be written at the very start of a ResourceDictionary (in another post I will explain how to organize the dictionaries) and it is the sole point where a color appears in the one I call the "sharped form" (remember the "#" in front of the color? ok you got the sharp).

#2 - Name your brushes

Ok, I'm reading clear on you the doubt. What the hell I can do with a bunch of colors? You all are right, colors are a form that is not ready to be used in your markup. 9 times over 10 a property of an element does not accept an instance of Color but instead it requires a Brush. So, as you did with colors, now you have to name your brushes. Brush names are more close to the real usage, and please keep in mind that nothing prevent you from use the same color in two or more brushes. Here is a set of brushes:

   1: <SolidColorBrush x:Key="BackgroundBrush" Color="{StaticResource ExtraLightColor}" />
   2: <SolidColorBrush x:Key="HighlightBrush" Color="{StaticResource LightColor}" />
   3: <SolidColorBrush x:Key="SelectionBrush" Color="{StaticResource LightColor}" />
   4: <SolidColorBrush x:Key="AlertBrush" Color="{StaticResource DarkColor}" />

As you can see, the brushes' name suggests the use you have to do with it. In this example you have Highlights and Selections rendered with the same LightColor and the AlertBrush is a DarkColor. This one is a good example of the naming: you do not need to have the Alert as Red, you only have to use a color that stands over the BackgroundColor. An the naming here helps you to remember the meaning instead of it color.

#3 - Name your gradients

Some applications make use of gradients. As you know gradients are simply a transition between a series of colors. And with your named colors you can for sure create a set of named gradients. Thanks to the Brush concept you can avoid to put gradients in the markup but you can easily put them side by side with the palette and the solid brushes and this way you are able in the future to change a solidcolor to a gradient and a gradient to a solidcolor:

   1: <LinearGradientBrush x:Key="SoftBrush" EndPoint="0.5,1" StartPoint="0.5,0">
   2:     <GradientStop Offset="0.0" Color="{StaticResource ExtraLightColor}" />
   3:     <GradientStop Offset="1.0" Color="{StaticResource LightColor}" />
   4: </LinearGradientBrush>
   5:  
   6: <LinearGradientBrush x:Key="ToolbarBrush" EndPoint="0.5,1" StartPoint="0.5,0">
   7:     <GradientStop Offset="0.0" Color="{StaticResource DarkColor}" />
   8:     <GradientStop Offset="1.0" Color="{StaticResource BasicColor}" />
   9: </LinearGradientBrush>

In my old applications I was use to call gradients as a named followed by "Gradient" but recently I've understand that it is a bad policy like naming Red as Red. You will understand it the first time you whant to flat your embossed toolbar and you transform a gradient to a solid brush.

#4 - Take advantage of Blend (with care)

imageOnce you have created a palette and a set of brushes you can start using them and Expression Blend is your best friend but you have to pay attention to something.

On the right side you see the color tool of Blend. Instead of it you see a tab named "Color Resources". Please always remember to never use it. This tab exposes the Color instances you named in your palette. At the first sight is may seems a good idea to select colors from here but is means you put a Brush in the markup and this brush wraps the color you have selected.

Just because Colors are not directly supported, Blend expose them to let you edit gradients easily but it wraps them into a brush before to set the property of the element you are editing. You have instead to use the last button on the very top of the window. It is named "Brush Resources" and it shows the brushes you have laboriously defined.

It is all about colors

As I've already said, your palette is the central point of the theme of your application. And planning themes carefully let you change the look & feel easily making its lifetime much more longer. XAML Resources are ten times more powerful than CSS and the content of this post is a good example of this power. As an interesting excercise, please try to reproduce the matter of this post in a CSS and you will understand that it is simply impossible.

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

Hierarchical binding with Implicit Data Templates

2012-01-12T23:52:41+01:00 by codeblock

Implicit data templates are a new interesting feature of Silverlight 5.0. They are a new way to create templates that automatically applies to specific types. So, imagine you have a set of types defined, and you want to present a collection of them inside an ItemsControl, you can use an Implicit Template that apply to each one of the types you are binding. Automatically this template will be applied to the give type every time it appear in the collection.

As you can figure out if may become really useful to present every item in a different way. Let say you have an Event base class and two derived Alarm and Information. You can bind the ItemsControl to an ObservableCollection<Event> as usual. Then you specify a different template for each one of the derived types:

   1: <ItemsControl ItemsSource="{Binding Events}">
   2:     <ItemsControl.Resources>
   3:         <DataTemplate DataType="om:Alarm">
   4:             <TextBlock Text="{Binding Message}" Foreground="Red" />
   5:         </DataTemplate>
   6:         <DataTemplate DataType="om:Information">
   7:             <TextBlock Text="{Binding Message}" Foreground="Black" />
   8:         </DataTemplate>
   9:     </ItemsControl.Resources>
  10: </ItemsControl>

Running the example you will get Alarm instances written in Red and Information instances written in black. The example is trivial just because I'm pretty sure you already read about Implicit Data Templates. The interesting thing to observe in this example i that you put templates in a Resources Section. This section apply to each one of the instances created inside of the ItemsControl.

After thinking a lot about this detail I realized you can use Implict Templates to bind Hierarchical structures and present each node with a different aspect based on the type ot the node. So I've taken the most obvious hierarchical structure - the filesystem - and I created a WCF method on top of it:

   1: public class FileSystemService : IFileSystemService
   2: {
   3:     public const string Root = @"C:\";
   4:  
   5:     public IEnumerable<FileSystemItem> GetItems(string path)
   6:     {
   7:         List<FileSystemItem> items = new List<FileSystemItem>();
   8:  
   9:         DirectoryInfo directory = new DirectoryInfo(Root + path);
  10:  
  11:         foreach (var item in directory.GetDirectories())
  12:         {
  13:             try
  14:             {
  15:                 items.Add(new Folder
  16:                 {
  17:                     Name = item.Name,
  18:                     HasChildren = item.GetFiles().Count() + item.GetDirectories().Count() > 0
  19:                 });
  20:             }
  21:             catch(UnauthorizedAccessException)
  22:             { }
  23:         }
  24:  
  25:         foreach (var item in directory.GetFiles())
  26:         {
  27:             items.Add(new File
  28:             {
  29:                 Name = item.Name,
  30:                 Size = item.Length
  31:             });
  32:         }
  33:  
  34:         return items;
  35:     }
  36: }

Two words about this code. It is a method that accept a string representing the path to retrieve. The method simply points to the specified path and enumerates Folders and Files adding a few information specific to the type. Size for the file and HasChildren for the Folder.

After this, the service is ready so it's time to create the proxy on the Silverlight project and then start creating the front end. For the best result I used the MVVM pattern and create a page with its ViewModel then a ViewModel for each of the types returned by the service.

   1: public class FileViewModel : FileSystemItemViewModel<File>
   2: { }
   3:  
   4: public class FolderViewModel : FileSystemItemViewModel<Folder>
   5: { }

At the first sight it may seems you can use directly the types that comes from the service but usig a ViewModel is the best choice because I have to get commands from the nodes and I need to lazy load children items. So indise the MainPage view model I start the chain loading the first level to present in the hierarchy:

   1: public class MainPageViewModel : ViewModelBase
   2: {
   3:     public ObservableCollection<ViewModelBase> Items { get; set; }
   4:  
   5:     public MainPageViewModel()
   6:     {
   7:         this.Items = new ObservableCollection<ViewModelBase>();
   8:         this.Load();
   9:     }
  10:  
  11:     private void Load()
  12:     {
  13:         FileSystemServiceClient client = new FileSystemServiceClient();
  14:         client.GetItemsCompleted += new EventHandler<GetItemsCompletedEventArgs>(client_GetItemsCompleted);
  15:         client.GetItemsAsync(string.Empty);
  16:     }
  17:  
  18:     private void client_GetItemsCompleted(object sender, GetItemsCompletedEventArgs e)
  19:     {
  20:         this.Items.Clear();
  21:  
  22:         foreach (var item in e.Result)
  23:         {
  24:             if (item is File)
  25:                 this.Items.Add(new FileViewModel(item as File));
  26:             else if (item is Folder)
  27:                 this.Items.Add(new FolderViewModel(item as Folder, string.Empty));
  28:         }
  29:     }
  30: }

Since the File will not have any action in this example, but in an extended example it may trigger the download of the file. For the purpose of the article I will concentrate on the FolderViewModel. When the item is clicked I expect that the children is loaded and presented in the UI. So here is the code:

   1: public class FolderViewModel : FileSystemItemViewModel<Folder>
   2: {
   3:     public FolderViewModel(Folder folder, string path)
   4:         : base(folder)
   5:     {
   6:         this.Path = path + "/" + folder.Name;
   7:         this.Items = new ObservableCollection<ViewModelBase>();
   8:         this.ClickCommand = new RelayCommand(Click);
   9:     }
  10:  
  11:     private void Click()
  12:     {
  13:         if (this.Items.Count == 0)
  14:         {
  15:             FileSystemServiceClient client = new FileSystemServiceClient();
  16:             client.GetItemsCompleted += new EventHandler<GetItemsCompletedEventArgs>(client_GetItemsCompleted);
  17:             client.GetItemsAsync(this.Path);
  18:         }
  19:         else
  20:             this.IsExpanded = !this.IsExpanded;
  21:     }
  22:  
  23:     private void client_GetItemsCompleted(object sender, GetItemsCompletedEventArgs e)
  24:     {
  25:         this.Items.Clear();
  26:  
  27:         foreach (var item in e.Result)
  28:         {
  29:             if (item is File)
  30:                 this.Items.Add(new FileViewModel(item as File));
  31:             else if (item is Folder)
  32:                 this.Items.Add(new FolderViewModel(item as Folder, this.Path));
  33:         }
  34:  
  35:         this.IsExpanded = true;
  36:     }
  37:  
  38:     // here starts the Binding properties...
  39: }

In this snipped I omitted the Binding properties but remember that IsExpanded, Items and ClickCommand are respectively a boolean that indicated if the node is open or not, a collection of the child nodes and the command the user triggers when he click the node. When this happens, the service is called, and the returned children are loaded into the Items properties. I think the logic is really straightforward.

Finally it is time to watch the XAML code. Using two Implicit Templates, It is really simple to create a hierarchical structure starting from a simple ItemsControl:

   1: <Grid.Resources>
   2:     
   3:     <DataTemplate DataType="vm:FolderViewModel">
   4:         <StackPanel>
   5:             <StackPanel Orientation="Horizontal" Margin="2">
   6:                 <Image Source="/Images/folder.png" Width="16" Height="16" />
   7:                 <HyperlinkButton IsEnabled="{Binding Item.HasChildren}" 
   8:                                  Command="{Binding ClickCommand}" 
   9:                                  Content="{Binding Item.Name}" 
  10:                                  Foreground="Black" />
  11:             </StackPanel>
  12:             <ItemsControl Visibility="{Binding IsExpanded, Converter={StaticResource b2v}}" 
  13:                           Margin="20,0,0,0" ItemsSource="{Binding Items}" />
  14:         </StackPanel>
  15:     </DataTemplate>
  16:     
  17:     <DataTemplate DataType="vm:FileViewModel">
  18:         <StackPanel Orientation="Horizontal" Margin="2">
  19:             <Image Source="/Images/file.png" Width="16" Height="16" />
  20:             <TextBlock><Run Text="{Binding Item.Name}" />(<Run Text="{Binding Item.Size}" /> Kb)</TextBlock>
  21:         </StackPanel>
  22:     </DataTemplate>
  23:     
  24: </Grid.Resources>
  25:  
  26: <ScrollViewer>
  27:     <ItemsControl ItemsSource="{Binding Items}" />
  28: </ScrollViewer>

The DataTamplate relative to the FileViewModel simply presents an image and the TextBlock for the name. The FolderViewModel instead refers to a DataTemplate containing another ItemsControl binded the the Items property. imageThanks to the propagation of the resources this ItemsControl again is able to generate children based on the same templates. Te result is a simple treeview that opens a node when you click on it. The Margin property indents the nodes and improve the TreeView aspect.

The figure on the side shows the final aspect of the treeview, decorated with beautiful images. The best thing is that you can create a lot of different nodes on the basis of the type you add to the collection.

I have to confess, at the first time I've tryied to generate this using a TreeView and a HierarchicalDataTemplate but I was unable to manage to have it working. It seems the HierarchicalDataTemplate does not support the implicit data templates.

The sole trick is given by the Converter I used to change the boolean type to a Visibility property. This let me to use the IExpanded property to show or not the ItemsControl.

If you are intersted in the working sample you can download it here. The code is complete and assumes you bind the service to the C:\ volume.

Download: XPG.ImplicitDataBinding (479Kb)

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

Create a 3d maze with Silverlight 5.0

2012-01-02T01:40:25+01:00 by codeblock

I would like to start this post saying I'm not a game development expert. During the first times of my work with computers I've been fashinated by the matter but I never gone deep on this development branch. Once I've meet the first time Silverlight 5.0 and I known about the 3D programming the first idea I had is to create a very simple maze as the one someone could write as the basis of a 3D game. In this post I want to briefly illustrate the work you can download at the end of the text. Here you can view a short video of the result of my work.

The maze in this video is made totally with the 3D API in Silverlight 5.0 and is totally compatible with the RTW bits. The maze is randomly generated every time you load the program and you can control the movement using the keyboard.

Generate the maze

imageAt the base of the example there is a random generation algorithm. I think there are lot of algorithms you can find on internet and probably the one I used is really simple, but it is really effective.

The maze if based on a square divided in a number of cells and every cell has a wall on every side. Once I decided the size of the side I fill the square of celle and then I choose a random cell on a side. Then I search for an adiacent cell to move to. If the cell exists I remove the walls betweek the two cells then I move to the new position.

The algorithm continue to crawl the cells while there are room to move. If during this loop I meet a position that have not a free adiacent cell I crawl back on my steps searching for some cell to move to. When the position returns to the very first position where I started so the work is finished and all the cells have been used. Here is the core of the algorithm I described:

   1: int progress = 0;
   2:  
   3: Stack<Cell> stack = new Stack<Cell>();
   4: this.Reset();
   5:  
   6: Cell cell = this.GetRandom(0);
   7: cell.Type = CellType.Enter;
   8: cell.Visited = true;
   9:  
  10: while (true)
  11: {
  12:     Cell adiacent = this.GetAdiacentNonVisited(cell);
  13:  
  14:     if (adiacent != null)
  15:     {
  16:         stack.Push(cell);
  17:         adiacent.Visited = true;
  18:         cell = adiacent;
  19:  
  20:         progress++;
  21:  
  22:         this.OnGenerationProgressChanged((int)(progress * 100.0 / (this.Width * this.Height)));
  23:     }
  24:     else
  25:     {
  26:         if (stack.Count > 0)
  27:             cell = stack.Pop();
  28:         else
  29:             break;
  30:     }
  31: }
  32:  
  33: cell = this.GetRandom(this.Height - 1);
  34: cell.Type = CellType.Exit;
  35:  
  36: this.OnGenerationCompleted();

The figure on the side shows the resulting maze that is generated by the algorithm. It is very close to the labyrinths you can find in puzzles magazines.

Create the 3D view

Once the maze has been calculated it is time to render it using Silverlight 3D API. The rendering is made creating a square plan representing the floor of the maze and then iterating over oll the cells and creating the remaining walls.

A wall is exactly a parallelepiped created on a side. Since the thickness of the square side is zero, the wall is created across this line. some point external and some point internal. To avoid gaps in the corners all the walls include the corner of the square, also if another wall already used the same space.

Untitled-1Silverlight 3D API let you create every kind of figure using a collection of edges. The edges are drawed to create triangles.  A triangle is the sole surface you can create connecting three edges, that for sure is part of a single plane. Every other surface you can create can be constructed using a collection of triangles but is not necessarily part of a single plane. So to create the rectangle representing a face of a wall you have to use two triangles.

On the left side you can see the aspect of a wall. The figure shows the triangles that compose the three visible faces of the wall. Remember that the other side has exactly the same faces in the opposite position.

Drawing with the API you have to create the vertices of the figure then create the triangles connecting the vertices with edges. The full collection of edges makes the figure and it is added to a greater collection that represents the entire drawing. This collection is used to draw the final scene. The following snippet shows how to create a single wall:

   1: private void AddWall(List<VertexPositionColor> edges, float xOffset, float zOffset, float xSize, float zSize)
   2: {
   3:     var wall = new List<VertexPositionColor>();
   4:  
   5:     Vector3 topLeftFront = new Vector3(xOffset, this.Height, zOffset + zSize);
   6:     Vector3 bottomLeftFront = new Vector3(xOffset, 0.0f, zOffset + zSize);
   7:     Vector3 topRightFront = new Vector3(xOffset + xSize, this.Height, zOffset + zSize);
   8:     Vector3 bottomRightFront = new Vector3(xOffset + xSize, 0.0f, zOffset + zSize);
   9:     Vector3 topLeftBack = new Vector3(xOffset, this.Height, zOffset);
  10:     Vector3 topRightBack = new Vector3(xOffset + xSize, this.Height, zOffset);
  11:     Vector3 bottomLeftBack = new Vector3(xOffset, 0.0f, zOffset);
  12:     Vector3 bottomRightBack = new Vector3(xOffset + xSize, 0.0f, zOffset);
  13:  
  14:     Color c1 = Color.FromNonPremultiplied(200, 200, 200, 255);
  15:     Color c2 = Color.FromNonPremultiplied(150, 150, 150, 255);
  16:     Color c3 = Color.FromNonPremultiplied(100, 100, 100, 255);
  17:  
  18:     // Front face
  19:     wall.Add(new VertexPositionColor(topRightFront, c1));
  20:     wall.Add(new VertexPositionColor(bottomLeftFront, c1));
  21:     wall.Add(new VertexPositionColor(topLeftFront, c1));
  22:     wall.Add(new VertexPositionColor(topRightFront, c1));
  23:     wall.Add(new VertexPositionColor(bottomRightFront, c1));
  24:     wall.Add(new VertexPositionColor(bottomLeftFront, c1));
  25:  
  26:     // Back face 
  27:     wall.Add(new VertexPositionColor(bottomLeftBack, c1));
  28:     wall.Add(new VertexPositionColor(topRightBack, c1));
  29:     wall.Add(new VertexPositionColor(topLeftBack, c1));
  30:     wall.Add(new VertexPositionColor(bottomRightBack, c1));
  31:     wall.Add(new VertexPositionColor(topRightBack, c1));
  32:     wall.Add(new VertexPositionColor(bottomLeftBack, c1));
  33:  
  34:     // Top face
  35:     wall.Add(new VertexPositionColor(topLeftBack, c2));
  36:     wall.Add(new VertexPositionColor(topRightBack, c2));
  37:     wall.Add(new VertexPositionColor(topLeftFront, c2));
  38:     wall.Add(new VertexPositionColor(topRightBack, c2));
  39:     wall.Add(new VertexPositionColor(topRightFront, c2));
  40:     wall.Add(new VertexPositionColor(topLeftFront, c2));
  41:  
  42:     // Left face
  43:     wall.Add(new VertexPositionColor(bottomLeftFront, c3));
  44:     wall.Add(new VertexPositionColor(bottomLeftBack, c3));
  45:     wall.Add(new VertexPositionColor(topLeftFront, c3));
  46:     wall.Add(new VertexPositionColor(topLeftFront, c3));
  47:     wall.Add(new VertexPositionColor(bottomLeftBack, c3));
  48:     wall.Add(new VertexPositionColor(topLeftBack, c3));
  49:  
  50:     // Right face 
  51:     wall.Add(new VertexPositionColor(bottomRightBack, c3));
  52:     wall.Add(new VertexPositionColor(bottomRightFront, c3));
  53:     wall.Add(new VertexPositionColor(topRightFront, c3));
  54:     wall.Add(new VertexPositionColor(bottomRightBack, c3));
  55:     wall.Add(new VertexPositionColor(topRightFront, c3));
  56:     wall.Add(new VertexPositionColor(topRightBack, c3));
  57:  
  58:     edges.AddRange(wall);
  59: }

When the entire scene has been created it is time to draw it to the viewport. While you are drawing the scene, the collection of edges does not change anymore because it represents the object to draw on the 3D space. What really changes is the position from where the scene is viewed. This position is a vector located in the 3D space and have a direction to it points. Imagine it as your eye pointing a direction in the space that plus or minus is the direction pointed by your nose. Another important component of a scene is the light source. My example uses a omnidirectional light source but for the sake of simplicity I will leave this argument open. So here is the code that create the scene.

   1: XNA3DMazeRenderer renderer = 
   2:     new XNA3DMazeRenderer(System.Windows.Media.Colors.Red, (float)this.CellSize, 5.0f);
   3:  
   4: IEnumerable<VertexPositionColor> edges = renderer.Render(this.Maze);
   5:  
   6: this.Buffer = new VertexBuffer(
   7:     GraphicsDeviceManager.Current.GraphicsDevice,
   8:     VertexPositionColor.VertexDeclaration,
   9:     edges.Count(),
  10:     BufferUsage.WriteOnly);
  11:  
  12: this.Buffer.SetData(0, edges.ToArray(), 0, edges.Count(), 0);

Then the code that creates/updates the camera. It is full of matricial maths but it simply creates two points on the space and then connect one to the other. The first is the position of the camera and the second is the position of the target pointed by the camera:

   1: private void UpdateCamera()
   2: {
   3:     float x = (float)(this.CellSize * this.Maze.Width * this.Observer.Position.X);
   4:     float y = (float)(this.CellSize * this.Maze.Height * this.Observer.Position.Y);
   5:     float course = (float)(this.Observer.Course * (Math.PI / 180.0));
   6:     float tilt = (float)(this.Observer.Tilt * (Math.PI / 180.0));
   7:     Vector3 cameraPosition = new Vector3(x, 3.0f, y);
   8:     System.Windows.Point target = 
   9:         new System.Windows.Point(x + Math.Sin(course) * 100.0, y + Math.Cos(course) * 100.0);
  10:     float elevation = (float)(3.0 + Math.Sin(tilt) * 100.0);
  11:     Vector3 cameraTarget = new Vector3((float)target.X, elevation, (float)target.Y);
  12:  
  13:     this.View =
  14:         Matrix.CreateLookAt(cameraPosition, cameraTarget, Vector3.Up);
  15: }

As you can see in the code I use an "Observer" object that represents the player in the maze. It has a X and Y position on the 2D surface of the game, a course from 0 to 360 degrees representing the direction to it is pointing and finally a Tilt property that is used to move up and down. These properties are connected with the keyboard actions and determines the movement of the player onto the game surface.

Moving the player and making walls solid

Viewing the maze rendered the first time is for sure wonderful, but the very great thing is being able to navigate inside it with the keyboard. Every time a property of the Observer object is updated the change is reflected externally with the Change event. The event cause the update of the camera position and then the redraw of the scene. Using up and down arrow you can move forward and backward and with left and right arrows it is possible to turn the course in these directions. Additionally you can use PageUp and PageDown to tilt up and down the camera as the player tilt the head.

To catch the keyboard events continuously I use a trick. This is because keyboard event in silverlight does not repeats automatically. Using a KeyboardState class I created I check for KeyUp and KeyDown changing the status of monitored keys. Then a timer changed the observer properties according with the pressed keys. This tecnique allows also to use more that a single key at a time allowing the observer to turn since it is moving forward.

Finally you have to face another problem. While you are moving you have to check for the presence of a wall and cancel the motion when the observer hits it. Without this check the observer will pass through walls missing a great part of the realistic representation of the scene. The following code tests the presence of a wall and eventually cancel the movement:

   1: private void Observer_Changing(object sender, ObserverChangingEventArgs e)
   2: {
   3:     double x = this.Maze.Width * this.CellSize * e.Position.X;
   4:     double y = this.Maze.Height * this.CellSize * e.Position.Y;
   5:  
   6:     Cell cell = this.Maze.CellAt(
   7:         (int)(this.Maze.Width * e.Position.X),
   8:         (int)(this.Maze.Height * e.Position.Y));
   9:  
  10:     Rect boundaries = new Rect(
  11:         cell.X * this.CellSize + 1.25,
  12:         cell.Y * this.CellSize + 1.25,
  13:         this.CellSize - 2.5,
  14:         this.CellSize - 2.5);
  15:  
  16:     e.Cancel = false;
  17:  
  18:     if (cell.Top.IsSolid && y < boundaries.Top) e.Cancel = true;
  19:     if (cell.Bottom.IsSolid && y > boundaries.Bottom) e.Cancel = true;
  20:     if (cell.Left.IsSolid && x < boundaries.Left) e.Cancel = true;
  21:     if (cell.Right.IsSolid && x > boundaries.Right) e.Cancel = true;
  22: }

The collision algoritm here is very simple. It creates a buffer around the walls of the cell where the observer is located and then tests if the position goes out of these boundaries.

Working with 3D

Working with 3D in silverlight is for sure interesting but it requires a good knowledge of 3D math to achieve good results. Every time you get something really effective since it is a low level API using it programming interface becomes mostly difficult. So if you need to work with 3D I suggest to use an hi level framework that abstracts the API and let you think in terms of solid figures instead of collection of edges. Balder is for sure a good example of what I mean: http://balder.codeplex.com/

Download: http://www.silverlightplayground.org/assets/sources/SLPG.Maze.zip (270kb)

Tags:   , ,
Categories:   Silverlight 3D
Actions:   E-mail | del.icio.us | Permalink | Comments (1) | Comment RSSRSS comment feed