Prague

30 04 2008

I usually only put stuff on here that are related to work, but I had such a great time that I just had to share it with you.

Me and my buddy Tristan went to Prague for 4 days, and boy, what a great city that is. It felt like we were away for at least a week.

I did go there before by the way, but as most people I know, it was a school trip, and I did not do anything more than party at night and sleep the rest of the day ;).

There are so many great things to see, and you can do almost anything on foot. The feeling of the place is so relaxed, it has a vibe that is hard to describe.

One warning though: don’t fall for the crowds that stand waiting in front of the clock, it is absolutely not worth the wait, you’ll know what I mean when you get there.

And of course we met some very interesting people from all over the world. If you are reading this: It was very nice meeting you, send me an e-mail and maybe we can meet again somewhere else in the world, good luck with your exam.

As a final thought: If you have never been in Prague, go there tomorrow, and you will understand why Prague has the most tourists in Europe after Paris.

Check out the pictures

*update 8-5-2008: Added another set of pictures from prague (part 2)

Robertjan Tuit

Technorati: ,,


Script# 0.5, CodePlex & Opensource!

24 04 2008

After a couple of months of complete silence, Nikhil Kotari has made us happy again. He released version 0.5 of his great project Script#.

If you are a front-end .NET AJAX developer and do not yet know/use this project: go check it out! I have been using it for about half a year now, and it has saved me months of development and debugging time.

Nikhil has also made the first step towards open sourcing it, as it now has it’s own CodePlex page. The plans are to make the source code available when the product hits its V1 mark.

Links:

Robertjan Tuit

Technorati tags:


Updating the UI Thread in SL2

18 04 2008

Just as in WPF, Silverlight only allows you to update the UI from a UI Thread. This is done trough the Dispatcher object. There are a lot of samples floating around but none did exactly what I was looking for.

Let’s say we have the following code:

// Create a new thread and Start it

new Thread(new ThreadStart(() =>

{

    // Do some NON UI Asynchronous work here       

    PopulateSomeDataFromOtherData();

 

    // THIS WILL NOT WORK

    UpdateUI();

}

The code starts a new thread, then does some work on the thread. And when it’s finishes it tries to update the UI, this will fail!

To make this work, we need to tell the UI thread to execute this code trough the Dispatcher object:

First you define a custom (empty) delegate:

public delegate void UpdateUIDelegate();

And then you change the erroneous previous code to:

// Create a new thread and Start it

new Thread(new ThreadStart(() =>

{

    // Do some NON UI Asynchronous work here       

    PopulateSomeDataFromOtherData();

 

    // Define an action to execute in the UI Thread

    UpdateUIDelegate action = new UpdateUIDelegate(() =>

    {

        //Update the UI

        UpdateUI();

    });

 

    // Tell the UI Thread (Dispatcher) to execute the action

    Application.Current.RootVisual.Dispatcher.BeginInvoke(action);

})

).Start();

The changes use the Dispatcher from the RootVisual to execute the action delegate. This will nicely update the UI from a non UI-Thread.

NOTE: The Dispatcher object used in this sample is from the RootVisual. But every Control has it’s own Dispatcher object. Use it when it’s available, it will save you a lot of debugging.

For some more info on Silverlight and Threading check:

Stay in the light!

Robertjan Tuit

 



Julie "Agile" Andrews

16 04 2008

Some people just have too much time on their hands:

Maybe it’s because they are developing "Agile"

Robertjan Tuit



InTrack Usability Slides and Demos

11 04 2008

Here are the slides and demos for the InTrack Session. I did remove the deepzoom demo, because it was too large.

The reason the files are still so big, is because I did leave the video files in. But with a bit of a connection this shouldn’t be a problem.

For a great deepzoom demo visit:

Robertjan Tuit



Silverlight 2 - MSN Video ListBox

9 04 2008

NOTE TO RSS READERS: Click this link to see the images and source code correctly.

This is just one of those days: I have been redoing my Silverlight project for 5 times now and tried about 10 ways to do the same thing. All resulting in nothing. Not the result I wanted and not an error, If I had any hair I would have pulled it out. But I guess the choice to go work with a beta product was my own.

Onto the real reason of this blog post: to prevent you from having the same terrible day. I was able to reproduce the error in a test project which will also demonstrate some nice features of SL that do work as expected :).

The end result

Usually I don’t begin with the end, but I always like to visualize what I’m going to make:

image

and we will be using a the Random MSN Video service as our data source:
http://catalog.video.msn.com/randomVideo.aspx?mk=us&vs=0&df=99&c=10

For the lazy (most of us developers/designers), here is the source code we are going to create:

New Project

We start out by creating a new Silverlight Project in this demo I assumed it to be named SilverlightApplication2:

image

And in the next screen select "Add a new Web to the solution for hosting the control" and select "Web Application Project".

image 

After the 2 projects are created, set SilverlightApplication2TestPage.aspx as your start page.

XML to Objects for Databinding

Silverlight does not yet support the direct XML databinding available in WPF. So we will have to do our binding by hand. First let’s create the data model we will be using: Add a new class "VideoFeedItem.cs" to the SilverlightApplication2 project with the following code:

public class VideoFeedItem

{

    public string Title { get; set; }

    public string Source { get; set; }

    public string PublishDate { get; set; }

    public string Description { get; set; }

    public string ImageUrl { get; set; }

    public string VideoUrl { get; set; }

    public string ViewCount { get; set; }

}

Then add a new class "VideoDS.cs" to the SilverlightApplication2 project, I have added code comments to explain what it does:

/// <summary>

/// This class will load from a webservice and

/// provide a datasource which we can bind to from XAML.

/// </summary>

public class VideoDS : INotifyPropertyChanged

{

    // Webservice URI & Namespace

    private const string _randomVideo = "http://catalog.video.msn.com/randomVideo.aspx?mk=us&vs=0&df=99&c=10";

    readonly XNamespace _NS = "urn:schemas-microsoft-com:msnvideo:catalog";

 

    // Bindable Collection

    public ObservableCollection<VideoFeedItem> RandomVideos { get; set; }

 

    public VideoDS()

    {

        // Only load the video feed when we are in the browser (Not in blend/VS)

        if (HtmlPage.IsEnabled)

            LoadVideoFeed();

    }

 

    /// <summary>

    /// Load the video feed and put it into our collection

    /// </summary>

    private void LoadVideoFeed()

    {

        // Use a normal webclient to fetch the feed

        var wc = new WebClient();

        // New lambda style delegate declaration

        wc.DownloadStringCompleted += (sender, e) =>

        {

            var doc = XDocument.Parse(e.Result);

            // Linq Select from the XML Tree and create a new VideoFeedItem for each selected.

            var videos =

              from video in doc.Descendants(_NS + "video")

              select new VideoFeedItem()

              {

                Title = (string)video.Element(_NS+"title"),

                Source = (string)(video.Element(_NS + "source").Attribute("friendlyName")),

                PublishDate = DateTime.Parse((string)video.Element(_NS + "startDate")).ToShortDateString(),

                Description = (string)video.Element(_NS + "description"),

                ImageUrl = GetUriAsset(video.Element(_NS + "files"), "file", "2007"),

                VideoUrl = GetUriAsset(video.Element(_NS + "videoFiles"), "videoFile", "1002"),

                ViewCount = (string)video.Element(_NS + "usage").Element(_NS + "usageItem").Attribute("totalCount"),

              };

 

            // Add the results to the Collection

            RandomVideos = new ObservableCollection<VideoFeedItem>();

            foreach (var video in videos)

                RandomVideos.Add(video);

 

            // Notify all listeners that the data has changed

            PropertyChanged(this, new PropertyChangedEventArgs("RandomVideos"));

        };

        wc.DownloadStringAsync(new Uri(_randomVideo));

    }

 

    #region LINQ Uri Helper

    /// <summary>

    /// Helps with the finding of some data in the complicated XML Structure

    /// </summary>

    private string GetUriAsset(XContainer element, string nodeName, string formatCode)

    {

        var uris = from file in element.Descendants(_NS + nodeName)

                                   where (string)file.Attribute("formatCode") == formatCode

                                   select (string)file.Element(_NS + "uri");

        return ((uris.Count<string>() > 0) ? uris.First<string>() : string.Empty);

    }

    #endregion

 

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion

}

Binding

Now that we have setup the classes necessary for the data loading and binding, let’s add the ListBox to our page.xaml. Page.xaml should look like this:

<UserControl x:Class="SilverlightApplication2.Page"

   xmlns="http://schemas.microsoft.com/client/2007"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"             

   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"             

   xmlns:SilverlightApplication2="clr-namespace:SilverlightApplication2"

   mc:Ignorable="d"

   Width="600" Height="200">

    <UserControl.Resources>

        <SilverlightApplication2:VideoDS x:Key="VideoDS" d:IsDataSource="True"/>

    </UserControl.Resources>

    <Grid x:Name="LayoutRoot">

        <ListBox ItemsSource="{Binding RandomVideos, 
                                Source
={StaticResource VideoDS}}"/>

    </Grid>

</UserControl>

You can now run the application, it should look like this:

image

Template

As you see here, the listbox has found our collection, but has no clue whatsoever what to do with it. To tell it how it should display our data, we add ListBox.ItemTemplate and we change the orientation using the ListBox.ItemsPanel property:

<ListBox ItemsSource="{Binding RandomVideos, Source={StaticResource VideoDS}}">

    <ListBox.ItemTemplate>

        <DataTemplate>

            <TextBlock Text="{Binding Title}"/> 

        </DataTemplate>

    </ListBox.ItemTemplate>

    <ListBox.ItemsPanel>

        <ItemsPanelTemplate>

            <StackPanel Orientation="Horizontal"/>

        </ItemsPanelTemplate>

    </ListBox.ItemsPanel>

</ListBox>

This should result in the following (with other data ofcourse since the video’s are random):

image

I’m always a big fan of the separation of design and behavior, so let’s move the properties to a style. First remove the properties and add a Style to the ListBox:

<ListBox Style="{StaticResource ListBoxStyle}" ItemsSource="{Binding RandomVideos, Source={StaticResource VideoDS}}"/>

Style

And then add a Style to the UserControl:

<UserControl.Resources>

    <SilverlightApplication2:VideoDS x:Key="VideoDS" d:IsDataSource="True"/>

    <Style x:Key="ListBoxStyle" TargetType="ListBox">

        <Setter Property="ItemsPanel">

            <Setter.Value>

                <ItemsPanelTemplate>

                    <StackPanel Orientation="Horizontal"/>

                </ItemsPanelTemplate>

            </Setter.Value>

        </Setter>

        <Setter Property="ItemTemplate">

            <Setter.Value>

                <DataTemplate>

                    <TextBlock Text="{Binding Title}" />

                </DataTemplate>

            </Setter.Value>

        </Setter>

    </Style>

</UserControl.Resources>

The above style does exactly the same thing as out previous properties does, so no changes in result here. As a design choice you could also add the Style to the Resources in the App.xaml.

Image Binding

Next we’ll add an Image to the mix. We’ll also add a StackPanel and some Margin to make it look a little bit better.

<Setter Property="ItemTemplate">

    <Setter.Value>

        <DataTemplate>

            <StackPanel Width="200">

                <TextBlock Text="{Binding Title}" HorizontalAlignment="Center" Margin="5,5,5,0"/>

                <Image Height="120" Stretch="Uniform" Source="{Binding ImageUrl}" HorizontalAlignment="Center" Margin="10,10,10,10"/>

            </StackPanel>

        </DataTemplate>

    </Setter.Value>

</Setter>

Build and run the project, it should look something like this:

image

UserControl in a Style

To get a little bit more control over the video, we are going to move the content of the <DataTemplate> to a User Control. Add a new Silverlight UserControl to the project with the name : VideoFeedItemControl.

Move the XAML from the <DataTemplate> to the new usercontrol:

<UserControl x:Class="SilverlightApplication2.VideoFeedItemControl"

   xmlns="http://schemas.microsoft.com/client/2007"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Grid x:Name="LayoutRoot">

        <StackPanel Width="200">

            <TextBlock Text="{Binding Title}" HorizontalAlignment="Center" Margin="5,5,5,0"/>

            <Image Height="120" Stretch="Uniform" Source="{Binding ImageUrl}" HorizontalAlignment="Center" Margin="10,10,10,10"/>

        </StackPanel>

    </Grid>

</UserControl>

And place the <VideoFeedItemControl> in the Page.xaml <DataTemplate>:

<Setter Property="ItemTemplate">

    <Setter.Value>

        <DataTemplate>

            <SilverlightApplication2:VideoFeedItemControl/>

        </DataTemplate>

    </Setter.Value>

</Setter>

Ready to go, build and run. Let’s see our end result:
image
Hey, wait a minute!? that’s not what we were aiming for. That’s empty!

We did not get any errors, everything seems to be working correctly, what happened here?

The error

This was the point where it got frustrating. It took me more than a day to figure out. Remember the namespace handling in the page.xaml? One of these was a reference to our own project. This was generated automaticaly.

I’m talking about this line:

xmlns:SilverlightApplication2="clr-namespace:SilverlightApplication2"

Nothing wrong with it, right?

If you know what the problem is, the fix is very simple. Add:
assembly=SilverlightApplication2.

It should now be:

clr-namespace:SilverlightApplication2;assembly=SilverlightApplication2

We build and we get:

image

That looks more like it!

So we only needed an assembly reference to the current assembly? Strange behavior.

I’m still looking for the reason, but at least it is fixed. The strangest thing is that if you would move the UserControl back to the normal page. The UserControl works normally without the need of the assemblyname= in the namespace declaration.

So it seems this only happens when a UserControl is used within a template or style declaration.

Would be nice to have

Ofcourse it is much more work to have running video’s in the listbox. And there are at least 20 more things I can think of that could nicely extend the sample.

Maybe next time :)

Stay in the light!

Robertjan Tuit

Technorati tags: ,


MSDN InTrack - User Experience

4 04 2008

Next week in Barneveld, The Netherlands there is another great User eXperience InTrack session with  Robert Kuunders from Opatel. This time however Robert has asked me to join him and add a little bit more technical InTrackSilverlight 2.0 stuff to the mix. And ofcourse I am very happy to join in.

We will go and explore User Experience, Expression Studio, Blend 2.5, Silverlight 2.0 and Visual Studio and do some nice developer designer workflow. Ofcourse we will also try to get a little discussion going on the subjects.

If you wish to join out little session, click on the link below to register yourself.

See you next week!

Links:
- MSDN InTrack - User Experience
- Register