Andrej Tozon's blog

In the Attic

NAVIGATION - SEARCH

Localizing the August 2011 Windows Phone Toolkit

Great news! A new version of Windows Phone Toolkit was released today. These bits target the “Mango” OS (which translates to SDK v7.1). The “pre-Mango” version (7.0) will follow in a short-while.

Download the Toolkit from Codeplex. Available also on NuGet.

One of the new features coming with this release is localization support. Localized strings are there mostly to support brand new Date and Time converters, but they also include a few strings used by Date and Time picker controls that were available in the previous release.

The strings are localized to 22 languages that are the languages, available the “Mango” OS. Chances are you’re going to be writing an application localized to a “non-Mango” language (yes, there are us who are still waiting!), so here’s a tip how to extend the toolkit localization features to your “unsupported” language. I’ll be using the Slovenian (my native) language as the example.

1. Download the toolkit binaries and source code from Codeplex:

2. Unzip the source code package and open the solution (PhoneToolkit.sln).

3. In Solution Explorer, locate the LocalizedResources folder. Copy the neutral language (US English) control resources file and rename it by appending target culture code to the filename (sl-SI is for Slovenian language):

loc1

4. Open the new ControlResources file by double clicking on it in Solution Explorer. Managed Resources Editor should appear, listing original strings.

5. Take some time and translate all strings into the target language. It will probably take an iteration or two to get it right (have to test it in a real case example). In case of Slovenian language, there’s also a slight problem with missing dual  forms (e.g. there are singular and plural, like 1 hour and >1 hours, but I can’t specify the string for 2 hours), plus some other language specifics I have yet to figure out how to work around them.

loc2

6. Build the project. It should compile (make sure you’re using tools for v7.1).

7. Go to the Bin\Debug folder (or Bin\Release, depending on your build configuration) and locate the sl-SI folder (or the one that matches your culture code). In it, there should be a Microsoft.Phone.Controls.Toolkit.resources.dll file. Copy folder to the safe place on your disk. You’ll need it whenever you start a new project leveraging the Windows Phone Toolkit..

8. You’re done with the Toolkit. Start a new Windows Phone project, add a reference to the new Toolkit, add resource files, etc., and start developing your localized application.

9. Because you’re targeting the unsupported language, don’t forget to add the following line to the application start:

Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;

That’s usually the first line in my App constructor. The other usual localization steps apply: Edit .csproj file to add supported cultures, set the neutral language, …

10. After building your application, you’ve got the application package (.Xap file). Before deploying it on your device or marketplace, copy the culture-specific folder containing the new localized dll (from step 7) into it. If you’ve chosen English as the neutral language, the folder with your culture code (sl-SI in my case) should already be in place.

Note: I didn’t have to change the AppManifest.xml file in Xap to include the new localized resource dll, but perhaps it’s a good idea to do so. You may also choose a more convenient method of including the resource file at design time to avoid file copying and changing the manifest file after each build.

11. That’s it! With localized resource file in place, your application should now display Toolkit’s resources in your own language.

loc3

This is a screen shot from the Sample application that comes with the new Toolkit.



On a path to a generic About page

Since every Windows Phone application should have some kind of About page, I wanted to see if I could build a generic page that I would reuse in my other apps. These are a few tips I picked up during building such a page:

1. The About page is rarely accessed so I put it in a separate assembly. This way I took some initial load off the main assembly and the About assembly can now easily be shared with other apps.

2. If you want to display the application icon on your About page, there is no need to create new graphics. Depending on your target size, you can choose from either ApplicationIcon.png (62x62) or Background.png (173x173) icons. To put the icon on your About page, use:

<Image Source="/ApplicationIcon.png" Stretch="None" />

And of course you can specify your own size and adjust the stretching attribute.

But don’t worry about the ApplicationIcon.png not being included in the About page project. With application icons being marked as Content, the contents of a Xap should look something like this:

image

By specifying an external link reference to the ApplicationIcon.png, the icon will be displayed regardless of it not being part of the project that contains it.

3. Static text. This includes titles, labels and text that will likely be the same across every application. If you’re not localizing your apps, you may as be well hard-coding strings into your XAML. But if you are, you would most definitely want to pull them from your resource files. In latter case, the standard localization guidelines apply. Again, don’t worry if your if your localization files are in your main assembly. The application will pick them up correctly regardless (even at design time).

<TextBlock x:Name="PageTitle" 
           Text="{Binding Strings.AboutTitle, 
                  Source={StaticResource LanguageResources}}" 
           Margin="9,-7,0,0" 
           Style="{StaticResource PhoneTextTitle1Style}"/>

4. Dynamic text. This includes the version number, application title and other text that will be unique to every application or its version. Some of these texts could be stored in resource files as well, but let’s look at the alternative options.

If you take a look at the AssemblyInfo.cs file of your main project (you’ll find it in the Properties folder), you’ll see it’s populated with some weird assembly attributes you don’t even care about (that’s because you’re setting and changing them from Visual Studio’s dedicated project properties page, but that’s not the point).
The point is that you can access all of these strings from code. All you have to do is get to the main assembly and read its custom attributes (which is what those lines from the AssemblyInfo file really). Here’s how:

Getting the main / entry assembly

The first thing is getting access to the correct – main (or entry) assembly. There are many ways to do that. At least one of those listed below should play nice with your your application architecture :

Assembly.GetExecutingAssembly() will get a reference to an assembly that’s executing that same code.

Assembly.GetCallingAssembly()will get a reference to an assembly of the method that called into this code.

The above methods don’t work well if the call is originating from the same dll. Exploring further…

Deployment.Current.EntryPointAssembly returns a name of the main assembly in pure string. You can use that to load the assembly with Assembly.Load(System.Windows.Deployment.Current.EntryPointAssembly). This will get you the main assembly, but it doesn’t feel right, so I finally settled with:

Application.Current.GetType().Assembly depends on using the Application static class, but since this is only used for a simple About page, that shouldn’t be  a significant problem.

Reading the attributes

I created the following helper method to read the attributes off an assembly:

private string GetAttribute<T>(Func<T, string> selector)
    where T: Attribute
{
    object[] attributes = assembly.GetCustomAttributes(typeof(T), true);
    if (attributes.Length == 0)
    {
        return "N/A";
    }
    T attribute = attributes[0] as T;
    return attribute == null ? "N/A" : selector(attribute);
}

GetCustomAttributes method overload above will return the only specified type of attribute you’re requesting, and the selector Func will read the value off of it. In the example of getting the Version attribute, here’s how you would use the function:

private string version;
public string Version
{
  get 
  {
    return version ?? 
      (version = GetAttribute<AssemblyFileVersionAttribute>(a => a.Version)); 
  }
}

For the application title, you would use the AssemblyTitle attribute:

private string title;
public string Title
{
  get 
  {
    return title ?? 
       (title = GetAttribute<AssemblyTitleAttribute>(a => a.Title)); 
  }
}

And so on…

And if you’d like, you can even create your own attributes, for example:

[AttributeUsage(AttributeTargets.Assembly, Inherited = false)]
[ComVisible(true)]
public class AssemblyContactAttribute : Attribute
{
    public string Email { get; private set; }
    public AssemblyContactAttribute(string email)
    {
        Email = email;
    }
}

Put that into the AssemblyInfo.cs file, as seen with other assembly attributes:

[assembly: AssemblyContact("myapp@tozon.info")]

and use the GetAttribute method similar to above examples.

You have just decorated your assembly with a new custom attribute that you can pull out at runtime.

By following those four points I was able to completely isolate my About page from main app(s) and adding the About page in my new apps is a matter of seconds. There is some convention involved of course (like the name of resources reference holding class), but I don’t see this as a problem. What do you think?



Windows Phone Pivot and loading content

Rewatching the Windows Phone Application Performance MIX10 talk by Jeff Wilcox, I took a note of one particular part where he clearly answers a question I’ve been asked a few times by now already. This question is based around the confusing statement that Pivot controls are supposed to be lazy loading their content pages, in contrast to Panoramas, which, at startup, would load all pages at once. The part that confuses developers the most is that when they start debugging their apps, they find out that Pivots load all their pages at startup too! How come? Aren’t Pivots loading pages only when needed?

Jeff explains this very clearly (fast forward to approx. minute 25) : “So the instant you go to a page, we pop up the Pivot, we’ll load  the content there. … …  Trouble is, we need to load more, because we want to provide a smooth experience when you pivot around. So we’re actually also loading, right after that first page comes up, we’ll kick off a load for both items on the left and the right.

See Jeff’s talk on the Channel 9 site.

What this means is that if your Pivot has only 2 or 3 pages, the startup performance won’t be that much different than when using a Panorama. If those 3 content pages are heavy on the load, use a lot of bindings etc., you can get into trouble. In some cases, loading a single content page on startup (and the rest when pivoted to) might actually result in a better experience than preloading all 3 pages.

Is there a way to override the default Pivot behavior and load only one content page on startup?

Of course there is.

The trick is to create a user control for each content page (which is a good idea anyway) and start it off with a Pivot control by specifying empty pages:

<controls:Pivot Title="My Pivot"
                LoadingPivotItem="OnLoadingPivotItem">
    <controls:PivotItem Header="Page 1" />
    <controls:PivotItem Header="Page 2" />
    <controls:PivotItem Header="Page 3" />
</controls:Pivot>

The LoadingPivotItem event will fire each time the Pivot would load a new content page. From MSDN documentation: “[LoadingPivotItem is an] Event for offering an opportunity to dynamically load or change the content of a pivot item before it is displayed.”

What you do during this event is check whether the content is loaded yet and if it isn’t, kick off the load. Something like:

private void OnLoadingPivotItem(object sender, PivotItemEventArgs e)
{
    if (e.Item.Content != null)
    {
        // Content loaded already
        return;
    }

    Pivot pivot = (Pivot)sender;

    if (e.Item == pivot.Items[0])
    {
        e.Item.Content = new Page1Control();
    }
    else if (e.Item == pivot.Items[1])
    {
        e.Item.Content = new Page2Control();
    }
    else if (e.Item == pivot.Items[2])
    {
        e.Item.Content = new Page3Control();
    }
}

One thing to have in mind though: make sure that any data you want to display on those content pages are loaded on the background thread (again – always a good idea) to allow the pages to load as quickly as possible.



NTK2011: Slides and sample code: MVVM

MVVM is a topic that can easily take hours of discussion. Unfortunately, I only had less then one to talk about (at least some of) its goals, parts and possible implementations. Below is my slide deck:

And the code: download

The code is structured in a way that helps you see the changes in the code while progressing through the samples. Just follow the numbers (e.g. MainPage1, MainPage2, and so on). It’s mainly Silverlight code, with the last example being example of an easy transition to Windows Phone.

The sample application is a conference app that lets you see available sessions. I removed the online data endpoint so the online samples won’t work, but you’ll get the feel using the offline data provider. Speaking of data providers, there are three (online/Ntk, using OData endpoint, Offline (loads Xml file from resources), and Json (same as Ntk, just for getting data in Json format – you know, for the phone Winking smile).

Once again, I have to stress out that code is for demo purposes only - while it’s minimized one end, it may be overly complicated on the other. Also, Silverlight Toolkit and JSON.NET libraries that were added through Nuget are not included in the zip.

Ah yes, the slides are in Slovenian language.



NTK 2011 Slides: Silverlight and NUI

I’m publishing the materials from my “Silverlight and NUI” talk from this year NT conference. The talk, where I took the time to dig a bit deeper into Silverlight multi-touch and web camera access capabilities, was part of the whole-day track, themed as “Building applications with NUI”.

[The slides are in Slovenian language]

During my talk, I made some references to the following applications and libraries:

And this is the source code of apps I’d shown: SilverlightNUI.zip:

TouchDemo: primary touch point are shown as blue ellipses, all secondary ones as orange. Pressing the ‘1’ key will bring floating red circles on the canvas – you can move them around if you like. The commented out code changes the behavior of touch events so the primary touch points are not propagated to mouse clicks.

TouchManipulations uses the above-referenced Multi-Touch behaviors that  let you move some pictures around. Keys ‘1’ and ‘2’ will bring up two rectangles that’ll stream your web cam feed, but in different manner: VIdeoBruh vs. ImageBrush with repeated Image captures. [Note: Images included are only placeholders – with the file length of 0 – you’ll have to replace them with proper files in order to run the demo]



Dynamic Forms Redux 2: Windows Phone 7

One of the more popular posts on my blog here were the Dynamic Forms for Silverlight series I did a couple of years ago. Dynamic forms are useful for cases when you want to compose a form on the server and the client just renders it based on the provided field types.

This days it’s all about Windows Phone 7 so I updated the sample to show how the same technique of creating custom forms on the client can work on the phone as well. The attached project contains both Silverlight and Windows Phone 7 projects, both sharing resources from the same shared project.

Source code for this article is available.

How it works

You compose your fields collection on the server, like in the following snippet:

Collection<DynamicFormField> form = new Collection<DynamicFormField>
{
    new DynamicFormField()
        {
            Caption = "Name: ",
            Type = typeof (string).FullName
        },
    new DynamicFormField()
        {
            Caption = "Last name: ",
            Type = typeof (string).FullName
        },
    new DynamicFormField()
        {
            Caption = "Email: ",
            Type = "#Email#"
        },
    new DynamicFormField()
        {
            Caption = "Phone: ",
            Type = "#Phone#"
        },
    new DynamicFormField()
        {
            Caption = "Birth date: ",
            Type = typeof (DateTime).FullName
        },
    new DynamicFormField()
        {
            Caption = "Is employed: ",
            Type = typeof (bool).FullName,
            Value = false.ToString()
        },
    new DynamicFormField()
        {
            Caption = "Signature: ",
            Type = "#Signature#"
        }
};

The above collection contains:

  • Name and Last name fields, which are regular strings (System.String),
  • Email and Phone fields, for which we want them to be special kinds of a string so we mark them as “#Email#” and #Phone#,
  • Birth date field – a regular Date,
  • Is Employed field, that is of type Boolean, and
  • Signature field, which will contain an actual written signature, therefore we mark it as "#Signature#-

On the client size, we use the same template selector I used in my previous posts, and templates for the above fields are defined as:

<Shared:FormFieldTemplateSelector DataType="{Binding Type}">
    <Shared:FormFieldTemplateSelector.DataTemplates>
        <Shared:TemplateSelectorDataTemplate DataType="System.String">
            <TextBox Text="{Binding Value, Mode=TwoWay}" Width="400" />
        </Shared:TemplateSelectorDataTemplate>
        <Shared:TemplateSelectorDataTemplate DataType="#Email#">
            <TextBox Text="{Binding Value, Mode=TwoWay}" Width="400" 
                     InputScope="EmailUserName" />
        </Shared:TemplateSelectorDataTemplate>
        <Shared:TemplateSelectorDataTemplate DataType="#Phone#">
            <TextBox Text="{Binding Value, Mode=TwoWay}" Width="400" 
                     InputScope="TelephoneNumber" />
        </Shared:TemplateSelectorDataTemplate>
        <Shared:TemplateSelectorDataTemplate DataType="System.DateTime">
            <Controls:DatePicker Value="{Binding Value, Mode=TwoWay}"
                                 Width="400" />
        </Shared:TemplateSelectorDataTemplate>
        <Shared:TemplateSelectorDataTemplate DataType="System.Boolean">
            <CheckBox IsChecked="{Binding Value, Mode=TwoWay}" />
        </Shared:TemplateSelectorDataTemplate>
        <Shared:TemplateSelectorDataTemplate DataType="#Signature#">
            <Shared:SignaturePanel Width="400" Height="100" 
                    Strokes="{Binding Value, Mode=TwoWay, 
                    Converter={StaticResource strokesConverter}}" />
        </Shared:TemplateSelectorDataTemplate>
    </Shared:FormFieldTemplateSelector.DataTemplates>
</Shared:FormFieldTemplateSelector>

If you questioned the use of #Email# and #Phone# custom types instead of regular strings, the above snippet should make it clear – those were hints, intended for the (Windows Phone) client, so it can set the right input scopes for those fields.

This is how the form looks after the user fills it up:

image

Source code is available. Note that it’s only intended for showcasing the specific features and it’s far from production quality. Silverlight Toolkit for Windows Phone 7 (v4.2011.2) binary is not included, but was pulled in through NuGet.



Twedge, a simple Silverlight 4 twitter widget

Today’s brief IM conversation about twedge reminded me about this project I put together in the last minute for a local conference last May. Twedge is a simple twitter widget, build with Silverlight 4. You can  specify some colors, time interval and search terms for displaying tweets through the InitParams, making it somewhat configurable. Uses layout states to  display the tweets, allows text selection and highlights links, #hashtags and @names.
I wanted to finish it properly before releasing it to the Codeplex, but with that not happening any time soon, I decided to do it regardless.

So there it is, twedge on Codeplex.

twedge
Run the live version



Top 5 blog posts of mine in 2010

Thought I’d give this one a try – 5 posts that were accessed by visitors of my blog the most and were posted in 2010:

1. Add version 4 components to your Silverlight 3 application with MEF: I wrote about using MEF (Managed Extensibility Framework) to import and offer additional capabilities to users that have Silverlight 4 installed (over the ones that only have Silverlight 3).
2. Reactive Extensions #3: Windows Phone 7: First look at Reactive Extensions for Windows Phone 7. I (re)used the same code I used with my Silverlight / WPF demos show ItemsControl items appearing with a nice animated way.
3. Silverlight Layout States with Reactive Extensions: This post laid the ground for the previous post, showing, how the effect is done.
4. Named & optional parameters in Silverlight 4: I wrote about named & optional parameters that were in the latest Silverlight 4 release. Mostly useful when dealing with Office interop.
5. Display “My Pictures” in Silverlight application at design time: An attempt to hack up a Silverlight design-time ViewModel that would look into your Pictures folder and display any pics that were there.

Thanks for visiting my blog!



Reactive.buffering.from event.

Reactive?

This post is continuing the series about Reactive Extensions, a powerful little framework currently available for .NET 3.5 & 4, Silverlight 3/4, Windows Phone 7 and JavaScript,  that Microsoft’s Dev Labs are working on.

Buffering?

In this post, I’ll look into two reactive operators that will help me shape my Windows Phone 7 app into something that could eventually be called a  game, even. Those operators are:

BufferWithTime. BufferWithTime() will buffer values, produced in a specified time interval, to publish them all at once when that interval ends. Take, for example, a logger service, where you don’t need to log all events at once; instead, you would check your log queue every minute or so and log all queued events in a batch.

BufferWithCount. BufferWithCount() does a similar thing, but instead of a Timespan value, it takes an integer that specifies the number of values to buffer, before publishing all buffered values.

From event?

We know the FromEvent() construction operator already – it-s used to observe the sequence of specified events, the observation starting upon subscribing to that sequence.

So?

Right… Ok, let’s take the code from the previous post and build on that. Where I left it off was having an ItemsControl with nine tiles in it. What I wanted to do next was make those tiles react to user mouse clicks…

So let’s go and do that, taking small steps.

The source code for this blog post is available from here.

To be able to subscribe to tiles’ mouse events, we first need to find the visual elements representing them. This may seem a difficult task at first, because ItemsControl’s Items property holds a collection of data items (in this case, those are letters), not their visual representations. It’s not, really. Actually, this is a Linq query that will project the collection of letters (data) to a collection of tiles (visuals) through the item container:

IEnumerable<DependencyObject> c = from i in list.Items
                                  select list.ItemContainerGenerator.ContainerFromItem(i);

We’re going to observe these tiles so we’ll turn them to an observable collection:

IObservable<DependencyObject> oc = c.ToObservable();

Now, here’s the trick. We’re going to use a single Linq expression that will notify the observer whenever a tile (any tile!) has been clicked with a mouse, handing it a reference to that tile:

IObservable<Control> ee = from i in oc
    from e in Observable.FromEvent<MouseButtonEventArgs>(i, "MouseLeftButtonDown")
    select VisualTreeHelper.GetParent(((Grid)e.EventArgs.OriginalSource).Parent) as Control;

The expression is three part:

  1. Take all tiles and
  2. subscribe to their MouseLeftButtonDown event and
  3. when that event happens, return a reference to the tile that raised that event (using VisualTreeHelper to get tile’s parent element, as for the item's data template shown below).

Subscribing to this observable sequence of tiles will enable us to react to tile MouseLeftButtonDown events:

ee.Subscribe(Reveal);

In reaction to the mouse down event, we’ll make the tile go into a “Selected” state:

private static void Reveal(Control control)
{
    VisualStateManager.GoToState(control, "Selected", true);
}

But for this, we need to adjust the tile’s data template first. This is a simple “two-sided element” template that flips slides when going between Selected and Unselected sides. Visual states are used to represent the state on each of the side and transitions between those states. I also added the third state – the Matched state will make the matched tiles disappear:

<DataTemplate x:Key="TileTemplate">
    <ContentControl>
        <ContentControl.Template>
            <ControlTemplate>
                <Grid x:Name="TileRoot"
                      RenderTransformOrigin="0.5,0.5"
                      Opacity="0"
                      Width="142"
                      Height="142"
                      Margin="5">
                    <Grid.Projection>
                        <PlaneProjection CenterOfRotationX="0" 
                                         RotationY="-90" />
                    </Grid.Projection>
                    <Grid.RenderTransform>
                        <ScaleTransform />
                    </Grid.RenderTransform>
                    <i:Interaction.Behaviors>
                        <ib:LoadedBehavior />
                    </i:Interaction.Behaviors>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="SelectionStates">
                            <VisualState x:Name="Unselected">
                                <Storyboard>
                                    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)"
                                                                   Storyboard.TargetName="front">
                                        <EasingDoubleKeyFrame KeyTime="0" Value="180" />
                                        <EasingDoubleKeyFrame KeyTime="0:0:1" Value="0" />
                                    </DoubleAnimationUsingKeyFrames>
                                    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)"
                                                                   Storyboard.TargetName="back">
                                        <EasingDoubleKeyFrame KeyTime="0" Value="180" />
                                        <EasingDoubleKeyFrame KeyTime="0:0:1" Value="0" />
                                    </DoubleAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Canvas.ZIndex)"
                                                                   Storyboard.TargetName="back">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <System:Int32>1</System:Int32>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                        <DiscreteObjectKeyFrame KeyTime="0:0:0.5">
                                            <DiscreteObjectKeyFrame.Value>
                                                <System:Int32>0</System:Int32>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                        <DiscreteObjectKeyFrame KeyTime="0:0:1">
                                            <DiscreteObjectKeyFrame.Value>
                                                <System:Int32>0</System:Int32>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Selected">
                                <Storyboard>
                                    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)"
                                                                   Storyboard.TargetName="front">
                                        <EasingDoubleKeyFrame KeyTime="0" Value="0" />
                                        <EasingDoubleKeyFrame KeyTime="0:0:1" Value="180" />
                                    </DoubleAnimationUsingKeyFrames>
                                        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)"
                                                                   Storyboard.TargetName="back">
                                        <EasingDoubleKeyFrame KeyTime="0" Value="0" />
                                        <EasingDoubleKeyFrame KeyTime="0:0:1" Value="180" />
                                    </DoubleAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Canvas.ZIndex)"
                                                                   Storyboard.TargetName="back">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <System:Int32>0</System:Int32>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                        <DiscreteObjectKeyFrame KeyTime="0:0:0.5">
                                            <DiscreteObjectKeyFrame.Value>
                                                <System:Int32>1</System:Int32>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                        <DiscreteObjectKeyFrame KeyTime="0:0:1">
                                            <DiscreteObjectKeyFrame.Value>
                                                <System:Int32>1</System:Int32>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Matched">
                                <Storyboard>
                                    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="UIElement.Opacity"
                                                                   Storyboard.TargetName="TileRoot">
                                        <EasingDoubleKeyFrame KeyTime="0" Value="1" />
                                        <EasingDoubleKeyFrame KeyTime="0:0:1" Value="0" />
                                    </DoubleAnimationUsingKeyFrames>
                                    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="UIElement.Opacity"
                                                                   Storyboard.TargetName="front">
                                        <EasingDoubleKeyFrame KeyTime="0" Value="0" />
                                    </DoubleAnimationUsingKeyFrames>
                                    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)"
                                                                   Storyboard.TargetName="TileRoot">
                                        <EasingDoubleKeyFrame KeyTime="0" Value="1" />
                                        <EasingDoubleKeyFrame KeyTime="0:0:1" Value="1.5" />
                                    </DoubleAnimationUsingKeyFrames>
                                    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)"
                                                                   Storyboard.TargetName="TileRoot">
                                        <EasingDoubleKeyFrame KeyTime="0" Value="1" />
                                        <EasingDoubleKeyFrame KeyTime="0:0:1" Value="1.5" />
                                    </DoubleAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Grid x:Name="back"
                          HorizontalAlignment="Left"
                          Height="142"
                          Margin="0"
                          VerticalAlignment="Bottom"
                          Width="142"
                          Background="{StaticResource PhoneForegroundBrush}">
                        <Grid.Projection>
                            <PlaneProjection RotationY="180" />
                        </Grid.Projection>
                        <TextBlock Text="{Binding}"
                                   FontSize="{StaticResource PhoneFontSizeExtraExtraLarge}"
                                   Foreground="{StaticResource PhoneAccentBrush}"
                                   VerticalAlignment="Bottom"
                                   HorizontalAlignment="Left"
                                   IsHitTestVisible="False"
                                   Margin="20,0,0,10" />
                    </Grid>
                    <Grid x:Name="front"
                          HorizontalAlignment="Left"
                          Margin="0"
                          VerticalAlignment="Bottom"
                          Background="{StaticResource PhoneAccentBrush}"
                          Width="142"
                          Height="142">
                        <Grid.Projection>
                            <PlaneProjection />
                        </Grid.Projection>
                        <TextBlock Text="{Binding}"
                                   FontSize="{StaticResource PhoneFontSizeExtraExtraLarge}"
                                   Foreground="{StaticResource PhoneForegroundBrush}"
                                   VerticalAlignment="Bottom"
                                   IsHitTestVisible="False"
                                   HorizontalAlignment="Left"
                                   Margin="20,0,0,10" />
                    </Grid>
                </Grid>
            </ControlTemplate>
        </ContentControl.Template>
    </ContentControl>
</DataTemplate>

The game

Great, now we’ve got ourselves a very simple game of revealing tiles. Sounds familiar? Yes, it looks a lot like a Memory  game.

In a Memory game, we’re dealing with pairs, right? Selecting two of the tiles makes up for a single turn in the game. If we take the existing observable collection and  additionally make it buffer to two elements, the observer will only going get notified when the user selects two tiles. But we also need to let the revealing animation to finish (lasts 1 second), so we have to delay the event publication for one second.

var ff = ee.BufferWithCount(2).Delay(TimeSpan.FromSeconds(1));

The OnNext handler will get both data items associated with the tiles, we just need to subscribe:

ff.ObserveOnDispatcher().Subscribe(OnPairRevealed);

The handler’s implementation at this point is this:

private void OnPairRevealed(IList<Control> tiles)
{
    string state = (char) tiles[0].DataContext == (char) tiles[1].DataContext ? "Matched" : "Unselected";
    VisualStateManager.GoToState(tiles[0], state, true);
    VisualStateManager.GoToState(tiles[1], state, true);
}

Matched and Unselected states are the only valid states to transition from the Selected state. Target state is determined by comparing letters on the tiles – if both letters are the same, it’s a match!

Making it work

There’s a tiny small thing left to make this all work. The previous version of this app was showing the initial tile animation only, and now we need to wire in the logic described in this post. Nothing easier – with existing animation sequence subscription, we only need to call the function when the initial sequence ends. So this:

.Subscribe(AddLetter);

becomes this:

.Subscribe(AddLetter, ObserveClicks);

Video and source code

See the application in action…

… and download source code.

Finishing

Reactive Extensions sure are a fun way to program – take a quick run through the source code to see how little code was required to get things moving as shown in the video.

In future posts I’ll shape up this app into more functional Memory game. Possibly end up wanting publishing it on the marketplace…

Oh, and Happy New Year everybody!



My “What’s new in Silverlight 4 demo” app

What’s new in Silverlight 4? Isn’t Silverlight 4, like, old news by now?

Well yes, as the matter of fact, this is one of those long overdue posts that have a hard time getting out. As I’ve been showing these demos since Silverlight 4 Beta came out, this is really the high time I release the source code… Especially when we’re looking to get a fresh preview of Silverlight 5 in the near future.

So here it is – the source code of my Silverlight 4 sample project.

You can also see the project live.

And the rundown of what you can expect to see in the demos:

Fluid layout : Layout states

The first thing you’ll notice when running the demo app is a few images finding it’s way on the screen from the left, sequentially, one by one, with a nice animation. This was done by using new layout states, found on the ListBoxItem. The new LayoutStates (BeforeLoaded, AfterLoaded, BeforeUnloaded) can be used to add a story to your ListBox items. With common ListBox, the effect of items just mysteriously appearing in the box can be confusing to the user, and the same goes for them suddenly disappearing from it. By using animation, you can tell the story of where they came from and why, as well as to where they go when they are removed. Or you just want to prettify your UI a bit. Whatever… Anyway, looking at the code for this reveals nothing really special – the items are simply added to the list:

MenuItems = new ObservableCollection<MenuItem>();

menuItems.Add(new MenuItem { Caption = "WB", ImageUri = new Uri("Assets/html.png", UriKind.Relative), DataContext = "WebBrowser" });
foreach (var videoDevice in CaptureDeviceConfiguration.GetAvailableVideoCaptureDevices())
{
    menuItems.Add(new MenuItem { Caption = videoDevice.FriendlyName, ImageUri = new Uri("Assets/video.png", UriKind.Relative), DataContext = videoDevice });
}
menuItems.Add(new MenuItem { Caption = "RTB", ImageUri = new Uri("Assets/rtb.png", UriKind.Relative), DataContext = "RichTextBox" });
menuItems.Add(new MenuItem { Caption = "Paste", ImageUri = new Uri("Assets/paste.png", UriKind.Relative), DataContext = "Paste" });
menuItems.Add(new MenuItem { Caption = "CLS", ImageUri = new Uri("Assets/clear.png", UriKind.Relative), DataContext = "" });

Nothing special, but there are a couple of tricks: first, to make items appearing one by one, I’ve used a timer:

DispatcherTimer startTimer = new DispatcherTimer {Interval = TimeSpan.FromSeconds(0.2)};
int menuItemCount = 0;
startTimer.Tick += (s, e) =>
                       {
                           MenuItems.Add(menuItems[menuItemCount]);
                           menuItemCount++;
                           if (menuItemCount >= menuItems.Count)
                           {
                               startTimer.Stop();
                           }
                       };
startTimer.Start();

There is actually a better way of doing this now – Reactive Extensions, which I blogged about a couple of posts ago.

Second, I’ve used the BeforeLoaded and AfterLoaded layout states for animating the ItemsControlItems to transition from “non-existing” state to “loaded-and-visible" state. In other words, make them appear on their place in the ItemsControl through animation.

Third – what’s an ItemsControlItem? Out of the box, LayoutStates are only set on the ListBoxItem, if you want to use them on a plain ItemsControl, which also serves as a base for the ListBox, you have to create some kind of workaround, which includes a new class for your item container – ItemsControlItem. See the code for the example.

TextBlock Text trimming

In the menu which appears on the left when you start the app, you may or may not see the text in one on more boxes trimmed. This is achieved with a new property called TextTrimming. Set it to WordEllipsis to enable the trimming:

image

WebCam support and VideoBrush

In the menu code above you might’ve noticed the CaptureDeviceConfiguration.GetAvailableVideoCaptureDevices() enumeration loop – that’s how you enumerate your video-capable devices. Have many webcams plugged in? They’ll all show up in your menu – with the same icon and their name, probably truncated (see above). Hover your mouse over it to reveal their full name in the tooltip.

Clicking the video icon will get you a box with live preview of video stream of the selected cam. The box is an ordinary Rectangle with its Fill property set to VideoBrush, pointing to the selected video device capture source.

Only one VideoBrush can consume a single capture source, but several visual elements can share the VideoBrush. Click on the same video icon again to get another icon with the same video feed.

If you’ve got more than one, you can click on additional video icons to get video feeds from your other cams.

Oh, and running inside browser, you’ll see a nice security dialog, asking you to confirm you’re ok with that cam go live.

MouseWheel support

With video box out on the canvas, hover your mouse over it and play with your mouse wheel – the box will shrink and expand. This is achieved through the MouseWheel event, which many of the Silverlight 4 controls have. Some of them already have their own implementation of the event, generally they don’t.

In this case, a created a MouseWheelBehavior that can be applied to an element to make it work (on a Canvas). You would probably have to adapt it to use it properly; for the sake of this app, it works ok.

The interesting thing here is that if you have a multi-touch monitor, you can try a pinch zoom gesture on the box and it should shrink/expand as well => nice to see Windows APIs being used in Silverlight.

By the way, in this demo, you can drag’n’drop items on the canvas around…

WebBrowser and WebBrowserBrush

WebBrowser in Silverlight is funny… Running the app inside browser and clicking the WB icon will get you a simple box with the “HTML is enabled only in Out-of-Browser mode.” text inside. Run the app outside the browser (installed) and you’ll see a ‘proper’ web page:

image

The links demonstrate different aspects of browser features. Note: the last link will work only when application is installed with elevated trust (set as default with the accompanying sample code).

Adding another “browser” by clicking on the WB icon for the second time will actually bring up a rectangle, filled with the WebBrowserBrush. WebBrowserBrush mimics the referenced WebBrowser appearance at the time it was called on. Because it’s a snapshot it doesn’t react on WebBrowser changes, but you can update it the WebBrowser’s current state by calling the Redraw () method on it.

Right Mouse Click

UIElements in Silverlight 4 support right button clicks in applications, which can be conveniently used to implement a context menu. In fact, Silverlight Toolkit has an implementation of this already ready to use. This application shows how simple it is to implement. Right-click on any of the added elements to change its shape.

RichTextBox Control

A few fresh controls were introduced with Silverlight 4, RichTextBox is one of them. The app shows the simplest demo of it.

NotificationWindow

When clicking a RTB (RichTextBox) icon, a notification window will be displayed on the bottom right corner – another new control. Works outside of the browser only.

Silverlight app as a drop target

Go to your pictures folder and drag some pictures onto the app canvas – they will be shown inside the application – shows integration with the “outside world” / your app can accept files drag’n’dropped into it.

Copy/Paste

Copy text or Xaml and paste it into the app – a text element or a drawing will appear on the canvas. I usually demo this with the Expression Design – draw a shape, choose some colors for stroke and fill, than copy its Xaml (select the shape, then press Ctrl+Shit+C / Copy XAML) and paste into the app. The Xaml will deserialize into a nice Silverlight shape.

Data binding enhancements

Silverlight 4 also extends the data binding with some new properties. In sample code, you’ll notice a couple of running time labels displayed in the bottom right corner of the screen – those will display how the new properties work: the StringFormat property will let you specify the string format right there in Xaml, the TargetNullValue property value will be displayed when the source property value is null, and the FallBackValue will be displayed when there’s an error with the binding itself.

Commanding

Buttons in Silverlight 4 can be assigned objects, implementing an ICommand interface, allowing for implementing separation pattern, well known from Silverlight’s older brother WPF. There are a few commands you’ll find in the sample project – FullScreenCommand, PrintCommand and DelegateCommand, the latter being mostly known for its use in MVVM pattern implementations.

Full Screen pinning

One of the best new Silverlight 4 features is definitely the ability to ‘pin’ the application to a non-primary monitor, which is especially handy for video players. To enable it, you just have to set the FullScreenOptions:

Application.Current.Host.Content.FullScreenOptions = isFullScreenWhenUnfocused ? FullScreenOptions.StaysFullScreenWhenUnfocused : FullScreenOptions.None;

Check the FullScreenCommand in source code for the implementation.

Printing

Basic printing was introduced with Silverlight 4 – you can construct individual printing pages and send them to the printer as bitmaps – enough for simple(r) scenarios, but much better things are on their way in Silverlight 5. PrintCommand shows the simplest possible implementation for printing a page visual.

Other

There are some other Silverlight 4 features you’ll find in the sample code and I won’t be discussing here. Like MEF (Managed Extensibility Framework) or COM interop. And .NET RIA Services, but I don’t know how well they’ll play since the project is dependent on an older version.

Feel free to explore the source code. Just note – it’s demo code so don’t expect much on a best practices side…