XAML Playground
about XAML and other Amenities

#wp8tip: Adapt images to different resolutions

2013-04-23T23:32:03+01:00 by Andrea Boschin

Windows Phone 8 comes with the support of multiple resolutions, that must be supported by new applications to cover all the available devices. As you can understand, it is really important to be able to support these new resolutions seamless, but it may be annoying when we have to deal with a number of images. Indeed, if vector graphics scales directly to all the resolutions, at the sole price of correctly design yout layout, with images you are forced to provide a different size to every resolution, if you want the best result.

To make my life easy, I wrote a simple attached property that enable me to easily specify the path of the image and have it updated with a resolution suffix. It is something similar to which it happens automatically in Windows 8. First of all a mini helper to convert an uri and add the resolution switch the path:

   1: public static class ResolutionHelper
   2:  {
   3:      public static Uri ToCurrentResolution(this Uri uri)
   4:      {
   5:          string uriString = uri.OriginalString;
   6:  
   7:          if (uriString.EndsWith(".jpg") || uriString.EndsWith(".jpeg") || uriString.EndsWith(".png"))
   8:          {
   9:              int dot = uriString.LastIndexOf('.');
  10:              uriString = uriString.Substring(0, dot) + "." + ResolutionHelper.CurrentResolutionString + uriString.Substring(dot, uriString.Length - dot);
  11:              return new Uri(uriString, UriKind.RelativeOrAbsolute);
  12:          }
  13:  
  14:          return uri;
  15:      }
  16:  
  17:      private static string CurrentResolutionString
  18:      {
  19:          get
  20:          {
  21:              if (App.Current.Host.Content.ScaleFactor == 100)
  22:                  return "screen-wvga";
  23:              else if (App.Current.Host.Content.ScaleFactor == 160)
  24:                  return "screen-wxga";
  25:              else if (App.Current.Host.Content.ScaleFactor == 150)
  26:                  return "screen-720p";
  27:              else
  28:                  throw new InvalidOperationException("Unknown resolution");
  29:          }
  30:      }
  31:  }

Once I have this tool class ready, it's easy to imagine to specify an uri to the image source and have it converted on the basis of the current resolution. I've tried a number of solutions but I finally found that writing a simple Attached property is the most simple and effective. Here is the extension:

   1: public class AutoScale : DependencyObject
   2: {
   3:     public static readonly DependencyProperty SourceProperty =
   4:         DependencyProperty.RegisterAttached("Source", typeof(Uri), typeof(Image), new PropertyMetadata(null));
   5:  
   6:     public static Uri GetSource(DependencyObject obj)
   7:     {
   8:         return (Uri)obj.GetValue(SourceProperty);
   9:     }
  10:  
  11:     public static void SetSource(DependencyObject obj, Uri value)
  12:     {
  13:         obj.SetValue(SourceProperty, value);
  14:  
  15:         Image image = obj as Image;
  16:  
  17:         if (image != null)
  18:         {
  19:             image.Source = new BitmapImage(value.ToCurrentResolution());
  20:         }
  21:     }
  22: }

The attached property has the advantage of making the trick seamless. Instead of writing the Source property in the XAML, I write tha "local.AutoScale.Source" property and is automatially update the underlying image:

   1: <Image local:AutoScale.Source="/Assets/Images/img.jpg" 
   2:        HorizontalAlignment="Center" 
   3:        VerticalAlignment="Center" Width="300" Height="300"/>

Model View ViewModel with Windows Store Application

2013-03-08T21:20:28+01:00 by codeblock

I reference here the slides from this night talk about the Model View ViewModel in a Windows Store app. The talk and the slides are in Italian but I figure out you can use google translate to get the translation in you language.

Model-View-ViewModel con Windows Store Apps

Thanks to all the people that listened to my presentation and asked me a question about this topic. If you need my help please feel free to contact me via blog contact form.

The “evil” in using “async void”

2013-02-19T01:57:03+01:00 by codeblock

Following a non-NDA session at the MVP Global Summit 2013, the speaker pointed me to an interesting argument that is the usage of “async” with methods returning void. This practice is used many times, more than you expect, and is a potential source of interesting bad issues that can cause unexpected crashes in your apps.

The problem with “async void” versus the opposite “async Task” is that a method declared this way is something like a “fire and forget”, where the fired part is the body of the method and the forget part may be the problem. Let say you have a situation like this:

   1: public void Run()
   2: {
   3:     try
   4:     {
   5:         DoSomething();
   6:     }
   7:     catch(Exception ex)
   8:     {
   9:         DisplayError(ex);
  10:     }
  11: }
  12:  
  13: public async void DoSomething()
  14: {
  15:     throw new Exception("Something gone wrong...");
  16: }

The “DoSomething” method here throws and exception, probably due to an error in its flow. The problem is that, when this method is called, the developer cannot use the “await” because the method is declared as “void”. So, when the exception is thrown, the “Run” method has already exited. The direct result is that the Exception is pushed to the UI Thread and in a Windows Store app this means that the app crashes, without any advice.

This situation is much more common they you expect. consider the Dispatcher.RunAsync method:

   1: Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
   2:     async () =>
   3:     {
   4:         // do something here...
   5:     });

The declaration of the RunAsync method requires a delegate declared as “void”, so when you ask for an async lambda, this is called as in the previous example. An exception in the body of the lambda expression causes exactly and application crash. The soluton is to wrap the RunAsync method is a mathod that returns a Task, so it can be awaited. So please, always avoid using “async void” in your code and you will not drive crazy trying to understand what is going wrong in your app.

Tip: a common error with Dependency Property metadata

2013-01-22T23:54:03+01:00 by Andrea Boschin

Recently someone pointed me to a malfunction on one of my examples. He sent me a repro project and, after I've run the example, I found the problem as he described it to me. But it took me a long time to figure out the reason. The problem was really simple: an instance of a templated control in a page seems to share a property with another instance of the same control in another page... This sounds impossible at first sight but if the property is a Dependency Property the issue is real. Here is the original code:

   1: public static readonly DependencyProperty ParallacticLayersProperty =
   2:     DependencyProperty.Register(
   3:         "ParallacticLayers", 
   4:         typeof(List<FrameworkElement>), 
   5:         typeof(ParallacticGridView), new PropertyMetadata(new List<FrameworkElement>()));

The code above may appear correct but it has an important issue. When a dependency property is used with a collection type, it is important to not initiate the metadata inline with the declaration, because the declaration of a static property only create a single instance that is shared by all the controls that use thid property. The correct example is the following:

   1: public static readonly DependencyProperty ParallacticLayersProperty =
   2:     DependencyProperty.Register(
   3:         "ParallacticLayers", 
   4:         typeof(List<FrameworkElement>), 
   5:         typeof(ParallacticGridView), new PropertyMetadata(null));

The collection datatypes only, make this problem evident, because once the property has been initialized it does not change the value. The observed behavior shows that the collection always adds the items without removing them. This apply to every XAML dialect...

Customized semantic zoom: an alternative to common grouping

2013-01-18T01:36:55+01:00 by Andrea Boschin

A really distinctive aspect of the Windows Store apps is a completely new way of displaying information, that not only suggest a very simplified design able to improve the importance of content, but also introduces new paradigms to make easy to browse the structure of the information. So they born a number of controls that supports scrolling beyond the size of the screen, that display elements of the right dimension for the fingers, that easily enable grouping to make simple to reach what the user needs. The cutting edge of this completely new interface if for seru the semantic zoom control that adds a thrid dimension to the browsing of data enabling a flawless navigation over grouped information.

The pinch and zoom gesture is becoming a common habit while using a Windows Store app but unfortunately the developers have always used this control as-is, without experimenting other ways of use the Semantic Zoom views. What people always forget is that the Semantic Zoom control is easily extensible and, with a low effort it is possible to create controls that shows customized views for one of the zoom levels or both.

During the development of the my app "EarthQuake Alerts" I've tried to overcome the now common groups/items way of using this control creating a map for the zoomed-out view. In the figure below you can see the two view of the main screen of the app.

screenshot_01172013_000205 screenshot_01172013_000210

As you can see while the zoomed-in view is a common GridView displaying grouped items, the zoomed out view shows a map with a number of flags. To understand the meaning of the flags you are to be aware that each flags belogs to a group in the SemanticZoom zoomed in. The position of the flag is calculated as the medium point between all the coordinates belonging to a group.

Implementing the ISemanticZoomInformation

If you explore the documentation of the two controls that currently can be used as part of a semantic zoom view you can see that both the GridView and ListView implement the ISemanticZoomInformation. Infact this interface is directly used by the SemanticZoom control to send and receive information about the interaction of the user to change the visual state. So from a point of view a control can notify about the selection of an item and the SemantiZoom acts changing the view from one to the other pointing the focus to the selected group or item. On the other side the SemanticZoom can ask the target to focus an item or notify when a change starts or ends. The interface contains a number of methods and properties. Here you can view the complete documentation on MSDN: http://slpg.org/VavDrp

In my case the implementation was very simple because the target map does not need to complex interactions like focusing an element. This is because the map extends to the whole screen and the focus is not really useful .The sole interaction I need to handle is the click on a flag that have to switch to the secondary view. To get this working I used the SemanticZoomOwner property. This property give a reference to the SemanticZoom that contains the control. So every time I receive the click of an item I call the following method:

   1: private void ApplySemanticZoom(IGeographicGroup<IGeographicPoint> item)
   2: {
   3:     this.CurrentItem = item;
   4:     this.SemanticZoomOwner.ToggleActiveView();
   5: }

This simple call is able to switch from the current mode (the map in ZoomedOut) an the detail (the ZoomedIn). After the switch has started you have to take care of some other aspects. These are implemenetd overriding some other simple methods:

   1: public void StartViewChangeFrom(SemanticZoomLocation source, SemanticZoomLocation destination)
   2: {
   3:     source.Item = this.CurrentItem;
   4:     destination.Item = this.CurrentItem;
   5: }
   6:  
   7: public void StartViewChangeTo(SemanticZoomLocation source, SemanticZoomLocation destination)
   8: {
   9:     destination.Item = source.Item;
  10: }

The first override is called when the control has started the swith from itself to the alternative view. In this method I set the Destination as the selected item. In the other method, when the control is called I simply set the destination as the source. Remember that the CurrentItem property contanis the element clicked.

Really it is all what you need to do. Given the very few documentaion on the internet I spend some hours to understand the point. But after I understand the meaning of every method the implementation has become easy like a breeze.

Windows 8 apps: Make your GridView parallactic

2012-10-24T00:46:33+01:00 by Andrea Boschin

Few months ago I wrote a post about a way to apply a parallactic effect to a GridView. Given that I explained the meaning of the "parallactic" term in that post, I assume you already know it. Unfortunately, the solution I explained was based on the use of a ScrollViewer to wrap a GridView. This was because the ScrollViewer exposes the ViewChanged event but the GridView don't. This is a minor issue in some cases, but lot of times the scrolling is not so smooth and fluid as the one of the GridView. Luckily XAML is so smart and beautiful that offers an alternative solution as the following video shows:

You have to be aware that all XAML controls are template based, as they are in Silverlight, and if you explore the template of the GridView you notice that is is based on an internal ScrollViewer. So, the idea is really simple in words; I can inherit a new control from the GridView, subtly change the template and attach to ScrollViewer events to update the parallactic background. Simle to say as it is simple to implement. First of all we have to change the template:

   1: <Setter Property="Template">
   2:     <Setter.Value>
   3:         <ControlTemplate TargetType="local:ParallacticGridView">
   4:             <Grid Background="{TemplateBinding Background}">
   5:                 <ItemsControl x:Name="ParallacticLayersElement" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
   6:                     <ItemsControl.ItemsPanel>
   7:                         <ItemsPanelTemplate>
   8:                             <Grid />
   9:                         </ItemsPanelTemplate>
  10:                     </ItemsControl.ItemsPanel>
  11:                 </ItemsControl>
  12:                 <Border BorderBrush="{TemplateBinding BorderBrush}" 
  13:                     BorderThickness="{TemplateBinding BorderThickness}" 
  14:                     Background="Transparent">
  15:                     <ScrollViewer x:Name="ScrollViewer" 
  16:                                   BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}" 
  17:                                   HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}" 
  18:                                   HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" 
  19:                                   IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}" 
  20:                                   IsHorizontalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsHorizontalScrollChainingEnabled}" 
  21:                                   IsVerticalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsVerticalScrollChainingEnabled}" 
  22:                                   IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}" 
  23:                                   IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}" 
  24:                                   TabNavigation="{TemplateBinding TabNavigation}" 
  25:                                   VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" 
  26:                                   VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}" 
  27:                                   ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}"
  28:                                   Background="Transparent">
  29:                         <ItemsPresenter HeaderTemplate="{TemplateBinding HeaderTemplate}" 
  30:                                         Header="{TemplateBinding Header}" 
  31:                                         HeaderTransitions="{TemplateBinding HeaderTransitions}" 
  32:                                         Padding="{TemplateBinding Padding}" />
  33:                     </ScrollViewer>
  34:                 </Border>
  35:             </Grid>
  36:         </ControlTemplate>
  37:     </Setter.Value>
  38: </Setter>




The yellow parts are the changes respect the original template. The add an outer grid that is used to contains the internal elements together with the added backgrounds. The ItemsControl instead let you to add a number of background elements that will be showed under the generated items, one on top of the other. The code is a fragment of a template that has to be put inside the generic.xaml. The next step is to implement the class of the control:

   1: public class ParallacticGridView : GridView
   2: {
   3:      private ItemsControl ParallacticLayersElement { get; set; }
   4:      private ScrollViewer ScrollViewer { get; set; }
   5:  
   6:      public static readonly DependencyProperty ParallacticLayersProperty =
   7:          DependencyProperty.Register("ParallacticLayers", typeof(List<FrameworkElement>), typeof(ParallacticGridView), new PropertyMetadata(new List<FrameworkElement>()));
   8:  
   9:      public List<FrameworkElement> ParallacticLayers
  10:      {
  11:          get { return (List<FrameworkElement>)GetValue(ParallacticLayersProperty); }
  12:          set { SetValue(ParallacticLayersProperty, value); }
  13:      } 
  14:  
  15:      public ParallacticGridView()
  16:      {
  17:          this.DefaultStyleKey = typeof(ParallacticGridView);
  18:      }
  19:  
  20:      protected override void OnApplyTemplate()
  21:      {
  22:          this.ParallacticLayersElement = this.GetTemplateChild("ParallacticLayersElement") as ItemsControl;
  23:  
  24:          foreach (FrameworkElement element in this.ParallacticLayers)
  25:              this.ParallacticLayersElement.Items.Add(element);
  26:  
  27:          this.ScrollViewer = this.GetTemplateChild("ScrollViewer") as ScrollViewer;
  28:          this.ScrollViewer.ViewChanged += ScrollViewer_ViewChanged;
  29:          base.OnApplyTemplate();
  30:      }
  31:  
  32:      private void ScrollViewer_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
  33:      {
  34:          foreach (FrameworkElement element in this.ParallacticLayersElement.Items.OfType<FrameworkElement>())
  35:          {
  36:              Thickness thickness = element.Margin;
  37:              var deltaX = (this.ScrollViewer.HorizontalOffset / this.ScrollViewer.ScrollableWidth) * (element.ActualWidth - this.ScrollViewer.ViewportWidth);
  38:              thickness.Left = -deltaX;
  39:              element.Margin = thickness;
  40:          }
  41:      }
  42:  }

The control has a ParallacticLayers property that is used to specify the items on the background. In the OnApplyTemplate I get a reference to the elements I need to manipulate. First of all the ScrollViewer which I attach the ViewChanges event. In the event handler I calculate the position of each layer with the same formula I've used in the previous article. To use the new control you can operate as follow:

   1: <controls:ParallacticGridView x:Name="gv" SelectionMode="None">
   2:     <controls:ParallacticGridView.ParallacticLayers>
   3:         <Image Stretch="UniformToFill" Source="Assets/Montreal_Twilight_Panorama_2006.jpg" Margin="0,0,0,0" />
   4:     </controls:ParallacticGridView.ParallacticLayers>
   5:     <controls:ParallacticGridView.ItemTemplate>
   6:         <DataTemplate>
   7:             <Border Width="150" Height="150" Background="#88FFFFFF" BorderThickness="1" BorderBrush="#88000000">
   8:                 <TextBlock FontSize="24" Text="{Binding}" 
   9:                            HorizontalAlignment="Center" 
  10:                            VerticalAlignment="Center" 
  11:                            Foreground="Black" />
  12:             </Border>
  13:         </DataTemplate>
  14:     </controls:ParallacticGridView.ItemTemplate>
  15:     <controls:ParallacticGridView.ItemsPanel>
  16:         <ItemsPanelTemplate>
  17:             <VariableSizedWrapGrid MaximumRowsOrColumns="4" VerticalAlignment="Top" Margin="100,100,100,0" />
  18:         </ItemsPanelTemplate>
  19:     </controls:ParallacticGridView.ItemsPanel>
  20: </controls:ParallacticGridView>

Interesting, in the ParallacticLayers property you can put more that one background. The result will be a set of backgrounds that scroll at a different speed.

Download: Elite.Parallactic.zip (7MB)

Windows 8 Apps: Change your project to run PlayReady successfully

2012-09-22T23:29:25+01:00 by Andrea Boschin

Today I wasted a lot of time to understand why, the code I wrote to implement PlayReady in a Windows 8 App didn’t work. I have ran the code lot of times, making changes to handle obscure hypothesis, just because my application was failing to load a DRM protected stream. When I finally found the error code issued by the MediaFailed event I went on the right way:

MF_MEDIA_ENGINE_ERR_SRC_NOT_SUPPORTED : HRESULT – 0x800700C1

I convinced myself that the problem wasn’t in the code but probably in the context I was compiling, this because the error 0x800700C1 means “is not a valid Win32 application”.

Comparing the project configuration with the one in the samples, I found the answer in a simple flag in the project configuration:

image

The “prefer 32-bit” flag is a new entry in the projects that target Microsoft .NET Framework 4.5. Its meaning is explained well in this post but in a few words in my case it was forcing the compiler to output to x86 (32-bit) instead of x64. Unfortunately PlayReady only supports 64bit runtime so, when the application ran it failed with the code I reported above.

So, when you’ll have to write applications that take advantage of the PlayReady SDK, please always remember to clear this flag because it is the sole way to have it working.

Windows 8 Metro series part #1

2012-09-12T00:25:31+01:00 by Andrea Boschin

Today, the last article of my series about Windows 8 "metro” applications I’m writing for http://www.silverlightshow.net has been published. The article is the first of the second part so it is the moment to collect together the work I’ve done up to july for the first part. If you like, the articles are available online on the SilverlightShow’s website at the addresser here reported:

 

Thanks to the great work the team made, the series is also available in a useful e-book, in the most common formats for your e-reader. You can buy it on the same website at this address http://www.silverlightshow.net/ebooks/win8_metro_1.aspx for only $2,99.

Metro: The SemanticZoom and the missing ItemTemplateSelector for ZoomedOutView

2012-09-07T23:41:11+01:00 by Andrea Boschin

Did you ever try to use the ItemTemplateSelector property for a grid view in SemanticZoom’s ZoomedOutView property? So the question is simpler than it appear: take a GridView, used to show items in a semantic zoom, - when the user zooms out - and try to give a different template to each item, using the usual template selector. And the answer is also simple: it does not work.

I suppose there is a good reason for this problem, but what it really matter to me is the solution. In a recent project I developed, the problem was really annoying and, after lot of try I found a work-around. The first thing to do is to setup the ZoomedOutView property:

   1: <SemanticZoom.ZoomedOutView>
   2:     <GridView ItemTemplate="{StaticResource ZoomedOutItemTemplate}" SelectionMode="None">
   3:         <GridView.ItemsPanel>
   4:             <ItemsPanelTemplate>
   5:                 <WrapGrid ItemWidth="300" ItemHeight="150" 
   6:                           VerticalAlignment="Center" HorizontalAlignment="Center" />
   7:             </ItemsPanelTemplate>
   8:         </GridView.ItemsPanel>
   9:     </GridView>
  10: </SemanticZoom.ZoomedOutView>

This is easy to understand given that there is nothing new. Please take only note I specified a simple ItemTemplate where the trick happens. The work-around is to use a ContentControl to map binding information and use the ContentTemplateSelector in place of the ItemTemplateSelector that is not working:

   1: <DataTemplate x:Key="ZoomedOutItemTemplate">
   2:     <ContentControl DataContext="{Binding Group}" Content="{Binding DataContext, RelativeSource={RelativeSource Mode=Self}}">
   3:         <ContentControl.ContentTemplateSelector>
   4:             <local:SemanticZoomTemplateSelector
   5:                 MajorTemplate="{StaticResource ZoomedOutItemMajorTemplate}"
   6:                 MinorTemplate="{StaticResource ZoomedOutItemMinorTemplate}"
   7:                 LightTemplate="{StaticResource ZoomedOutItemLightTemplate}"
   8:                 StrongTemplate="{StaticResource ZoomedOutItemStrongTemplate}"
   9:                 ModerateTemplate="{StaticResource ZoomedOutItemModerateTemplate}" />
  10:         </ContentControl.ContentTemplateSelector>
  11:     </ContentControl>
  12: </DataTemplate>

The tricky part of the solution is into the DataBinding of the ContentControl. If you simply try to bind the source property to the Content property, the template selector is not applied. I supposed the reason has to be found in the way the data binding happens so I had the idea of binding the property twice: first of all I bind the source to the DataContext property and then I use the RelativeSource to bind the Content property to the DataContext. And… it works!

Now I can implement the a Template selector to assign the right template based on the values of the source item:

   1: public class SemanticZoomTemplateSelector : DataTemplateSelector
   2: {
   3:     public DataTemplate MinorTemplate { get; set; }
   4:     public DataTemplate MajorTemplate { get; set; }
   5:     public DataTemplate ModerateTemplate { get; set; }
   6:     public DataTemplate StrongTemplate { get; set; }
   7:     public DataTemplate LightTemplate { get; set; }
   8:  
   9:     public SemanticZoomTemplateSelector()
  10:     {
  11:     }
  12:  
  13:     protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
  14:     {
  15:         EarthquakeGroup group = item as EarthquakeGroup;
  16:  
  17:         if (group != null)
  18:         {
  19:             if (group.Level == "major")
  20:                 return MajorTemplate;
  21:             if (group.Level == "minor")
  22:                 return MinorTemplate;
  23:             if (group.Level == "moderate")
  24:                 return ModerateTemplate;
  25:             if (group.Level == "strong")
  26:                 return StrongTemplate;
  27:         }
  28:  
  29:         return LightTemplate;
  30:     }
  31: }

The best thing of this solution is that the ContentControl does not changes how the item is shown. It does not require any change to the data templates and you can also use a resource dictionary.

If the solution is not clear here is a downloadable example: http://xamlplayground.org/assets/sources/XPG.MetroQuakes.zip (22kb)

SilverlightPlayground is moving to XAMLPlayground

2012-07-01T16:00:00+01:00 by codeblock

In the day I got my MVP for the 6th time in a row (the fifth under the Silverlight expertise), I would like to make it official, a change that someone can have miss. If you watch at the page header of this site, the title is now "XAML Playground", just to be witness of a biggest change that has happened in the previous months.

Many of you are aware that, after the technology shift predicted by Bob Muglia during October 2010, lot of things have changed in the horizon of the technology from which this site has born. Silverlight today is not only Silverlight but a set of technologies now have their roots starting from its seed. We have Silverlight on the Windows Phone, we have Silverlight on the Embedded systems and, mostly important we have Silverlight on Windows 8 under the name of XAML.

And it is exactly reflecting the name change that happened in Windows 8, that I decided to slightly change the title from "Silverlight" to "XAML".

The reason of this change is probably clear. I strongly believe that the power of Silverlight is now part of something much more bigger and it has a bright future. All these technologies have a sole common denominator that is XAML.

So, as it happened since the start of this year, expect in the future, a number of posts on Silverlight in the various flavour, for the Web, for Windows Phone, for Metro UI and probably also for Windows (ops... WPF). 

From now please be aware you can use three domains to reach this site:

http://www.silverlightplayground.org

http://www.xamlplayground.org

http://www.metroplayground.org

So definitely, it is all about XAML

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

Metro: Incrementally load GridView and ListView with ISupportIncrementalLoading

2012-06-10T21:58:36+01:00 by codeblock

Developers that usually deal with web applications know that one of the pillar of this kind of applications is the use of paged result sets because moving a huge number of records form the server to the browser is not a good idea. Metro applications suffer the same problem. No matter that metro applications are not strictly web applications, the application architecture imply that the connection to a datasource have to be wrapped by web service call so the need of limiting the usage of the network is a strong requirements.

Metro introduces a new interesting method to mange pagine of data. Since the use of a common paging is deprecated by guidelines the requirement is to automatically load records when a user is about to the end of the items available on the user interface. This may be an hard task to do with components like GridView and ListView but thanks to the ISupportIncrementalLoading interface it may be easy like a game.

The ISupportIncrementalLoading interface has to be implemented by a collection. When a GridView detects this interface in the class provided in the ItemsSource property, it automatically change its behavior and works loading items only when they really need to fill empty space because the user reached the end. The definition of the interface is pretty simple:

   1: public interface ISupportIncrementalLoading
   2: {
   3:     bool HasMoreItems { get; }
   4:     IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count);
   5: }

The HasMoreItems property simply inform the consumer when there is more items to load. But the core of the interface is the LoadMoreItemsAsync method. As the name suggests this method works asynchronously and it have to load a number of items. The count parameter represents the number of items the consumer needs but the body of the method can load a different number, based on its paging size, and have to return the this number as a result into the LoadMoreItemsResult class.

You may expect that the loaded items have to be returned by this method but it is not true. Remembering that the interface have to be implemented by a collection, the method have simply to append the loaded items to the collection itself. So, this interface needs that the collection raises a CollectionChange event to update the user interface. An exaample is for sure much more clear:

   1: public class NaturalNumbers : ObservableCollection<int>, ISupportIncrementalLoading
   2: {
   3:     public bool HasMoreItems
   4:     {
   5:         get { return true; }
   6:     }
   7:  
   8:     public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
   9:     {
  10:         CoreDispatcher dispatcher = Window.Current.Dispatcher;
  11:  
  12:         return Task.Run<LoadMoreItemsResult>(
  13:             () =>
  14:             {
  15:                 int[] numbers = Enumerable.Range(this.LastOrDefault(), 100);
  16:                 
  17:                 dispatcher.RunAsync(
  18:                     CoreDispatcherPriority.Normal,
  19:                     () =>
  20:                     {
  21:                         foreach (int item in numbers)
  22:                             this.Add(item);
  23:                     });
  24:     
  25:                 return new LoadMoreItemsResult() { Count = 100 };
  26:     
  27:             }).AsAsyncOperation<LoadMoreItemsResult>();
  28:     } 
  29: }

If you attach an instance of this class to a GridView (or a ListView) it will show a series of natural numbers loading them incrementally when you scroll the control. Every time the GridView reach the edge of the screen it needs to load a number of items so, after having checked the HasMoreItems propertyit call the LoadMoreItemsAsync method and await for the end of the operation. Inside this method I start a new Task. This is required because I have to return something to wait to the caller and the AsAsyncOperation converts the Task to the requested async operation. Inside the thread I generate 100 numbers starting from last in the collection then I marshal this numbers to the ui thread and load them to the collection. Since the collection is Observable this updates the items in the user interface. Finally i return the number of items I generated.

As a more complex exercise I've prepared an example attached to the end of this post. This example use the incremental strategy to load images from Flickr search API. The application shown in the following screenshot implements the search contract. When a query is made it load a special collection and the items are loaded incrementally when the user scrolls the GridView.

screenshot_06102012_224133

For this purpose I've created a IncrementalSource class. This class implements the ISupportIncrementalLoading interface and is able to manage every data source that exposes a GetPage method. If you have this method already implemented in an application you can easily turn it to incremental loading in a breeze.

   1: public class IncrementalSource<T, K> : ObservableCollection<K>, ISupportIncrementalLoading
   2:     where T: IPagedSource<K>, new()
   3: {
   4:     private string Query { get; set; }
   5:     private int VirtualCount { get; set; }
   6:     private int CurrentPage { get; set; }
   7:     private IPagedSource<K> Source { get; set; }
   8:  
   9:     public IncrementalSource(string query)
  10:     {
  11:         this.Source = new T();
  12:         this.VirtualCount = int.MaxValue;
  13:         this.CurrentPage = 0;
  14:         this.Query = query;
  15:     }
  16:  
  17:     #region ISupportIncrementalLoading
  18:     
  19:     public bool HasMoreItems
  20:     {
  21:         get { return this.VirtualCount > this.CurrentPage * 25; }
  22:     }
  23:  
  24:     public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
  25:     {
  26:         CoreDispatcher dispatcher = Window.Current.Dispatcher;
  27:  
  28:         return Task.Run<LoadMoreItemsResult>(
  29:             async () =>
  30:             {
  31:                 IPagedResponse<K> result = await this.Source.GetPage(this.Query, ++this.CurrentPage, 25);
  32:                 
  33:                 this.VirtualCount = result.VirtualCount;
  34:  
  35:                 await dispatcher.RunAsync(
  36:                     CoreDispatcherPriority.Normal,
  37:                     () =>
  38:                     {
  39:                         foreach (K item in result.Items)
  40:                             this.Add(item);
  41:                     });
  42:  
  43:                 return new LoadMoreItemsResult() { Count = (uint)result.Items.Count() };
  44:  
  45:             }).AsAsyncOperation<LoadMoreItemsResult>();
  46:     } 
  47:  
  48:     #endregion
  49: }

In my example I've implemented a Flickr class that use the flickr.photos.search API. So when a search comes I create an instance of this collection in the ItemsSource property of the GridView.

this.gv.ItemsSource = new IncrementalSource<Flickr, FlickrPhoto>(search);

If you want to try this beautiful application please download the full code from the link below. Provide your own Flicks Api Key and run the example in Visual Studio 2012 RC.

Download: http://www.silverlightplayground.org/assets/sources/XPG.Examples.IncrementalLoading.zip

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

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