| Comments

Just a little post to point out a hidden gem if you are a .NET developer creating a Metro style app: you can bind to anonymous types.  This came up in a discussion with a customer today that I was having and, frankly, I never tried it until then because my mind was back in Silverlight where this isn’t possible.  There may not be a tone of cases where this is valuable for you, but knowing it is there may help.

Let’s assume I have a basic class Person:

   1: public class Person
   2: {
   3:     public int Age { get; set; }
   4:     public string FirstName { get; set; }
   5:     public string Gender { get; set; }
   6: }

And in my application I have a list of that Person type that I somehow received.  In this example, I’m just hard-coding it right now.

   1: List<Person> people = new List<Person>();
   2: people.Add(new Person() { Age = 38, FirstName = "Tim", Gender = "Male" });
   3: people.Add(new Person() { Age = 9, FirstName = "Zoe", Gender = "Female" });
   4: people.Add(new Person() { Age = 5, FirstName = "Zane", Gender = "Male" });

I can then decide I want to bind to a ListView control which has a particular template:

   1: <ListView x:Name="PeopleList" Width="500" Height="300">
   2:     <ListView.ItemTemplate>
   3:         <DataTemplate>
   4:             <StackPanel Orientation="Horizontal">
   5:                 <TextBlock Text="{Binding TheName}" Margin="0,0,10,0" />
   6:                 <TextBlock Text="{Binding GuysAge}" />
   7:             </StackPanel>
   8:         </DataTemplate>
   9:     </ListView.ItemTemplate>
  10: </ListView>

Notice that I’m binding to properties (TheName and GuysAge) that don’t exist on my Person class?  In my code, I can then create a LINQ query to filter out only the “dudes” from my list and bind that result:

   1: var onlyGuys = from g in people
   2:                where g.Gender == "Male"
   3:                orderby g.FirstName descending
   4:                select new
   5:                {
   6:                    GuysAge = g.Age,
   7:                    TheName = g.FirstName,
   8:                    Gender = "Dude"
   9:                };
  10:  
  11: PeopleList.ItemsSource = onlyGuys;

The result is that my ListView now shows 2 people in the list.  Nice.

Get in the real world

Now I would probably agree that since you already have a strongly-typed class this is probably not the use case here.  It certainly might be helpful, but you already have a class (and in this example, one that you completely control so you could shape it to be what you really need).  What about those times you don’t have a class or you don’t own the type coming back?  JSON ring a bell?  Using the sample JSON response (I’m not focusing on how to retrieve data here just how to bind to it) from Twitter APIs, we can demonstrate how this might be more helpful.  Here’s the Twitter JSON data I’m referring to in this example: Twitter Mentions API.

My app wants to retrieve and bind to Twitter data but I don’t really want to have a “TwitterResponse” data type that I have to serialize in/out in my code.  The mention data is an array of mentions.  For the sake of simplicity I’ve basically put my JSON string in a file rather than confuse this sample in how to work with Twitter.  My code looks like this (assume that ‘data’ is the resulting Twitter mentions JSON string:

   1: // parse the data into a JsonArray object
   2: var mentions = JsonArray.Parse(data);
   3:  
   4: // build the query out of the mentions
   5: var qry = from m in mentions
   6:           select new
   7:           {
   8:               MentionText = m.GetObject()["text"].GetString(),
   9:               FromUser = m.GetObject()["user"].GetObject()["screen_name"].GetString(),
  10:               ProfilePic = m.GetObject()["user"].GetObject()["profile_image_url"].GetString()
  11:           };
  12:  
  13: MentionData.ItemsSource = qry;

Notice the LINQ query for creating a “new” type that I will bind to my ListView.  In my XAML I have a simple DataTemplate to demonstrate:

   1: <ListView x:Name="MentionData" Width="500" Height="300">
   2:     <ListView.ItemTemplate>
   3:         <DataTemplate>
   4:             <StackPanel>
   5:                 <TextBlock Text="{Binding FromUser}" />
   6:                 <TextBlock Text="{Binding MentionText}" TextWrapping="Wrap" />
   7:             </StackPanel>
   8:         </DataTemplate>
   9:     </ListView.ItemTemplate>
  10: </ListView>

The result is me being able to create a LINQ query and create a new anonymous type and directly bind to it.

Voila!  Perhaps you already discovered this little gem and are using it.  It is a welcome addition to the data binding story for Metro style app development with XAML and .NET!  Of course the same benefit can be had for XML data using XLINQ queries, so while this example is for JSON data, really any source data applies…it is all about that new anonymous type you create!

Hope this helps!

| Comments

This is part 4 in a series on getting started with Silverlight.  To view the index to the series click hereYou can download the completed project files for this sample application in C# or Visual Basic.

In the previous step 3 we did a lot of work to get back our data from a public web service and display it in a control.  The DataGrid control we used, however, isn’t really the UI we’re looking for so let’s define what we want.  To do this we’re going to use an ItemsControl and a DataTemplate.  This will introduce us to XAML binding syntax and how to leverage more powerful data binding information.

Starting the UI over – delete the DataGrid

Well, after all that work, let’s delete the DataGrid and just the DataGrid.  We won’t be needing the assembly reference or the xmlns:data values anymore as well, so go ahead and remove them.

Replace the DataGrid with an ItemsControl like this:

   1: <ItemsControl x:Name="SearchResults" Margin="0,8,0,0" Grid.Row="1" />

Now here is where Blend is going to be helpful for us again.  Go into Blend and we’re going to modify the ItemTemplate for the ItemsControl.  ItemsControl is just essentially a rendering control that does what we tell it to.  If we do nothing but change the DataGrid to an ItemsControl and run our application this is what we’ll get:

ItemsControl rendering with no template

The ItemsControl has no idea how we want to display the data, so we have to tell it how in a template…back to Blend.  The general concept we’re going to go for is this (repeated of course):

ItemsControl template mockup

where the box is the avatar of the user posting the message.  Using our knowledge of layout from the previous steps we can create the template easily.  In Blend, locate the SearchResults object in the tree and right click to edit the ItemsTemplate (under the Generated Templates section):

Edit Generated Items menu option

we now have an empty template we can put stuff in.  I called mine SearchResultsTemplate in the dialog that came up.  Now we are in layout editing mode and can drag/move/etc items in our layout.  I created a Grid-based layout and here’s my resulting XAML for the template:

   1: <DataTemplate x:Key="SearchResultsTemplate">
   2:     <Grid Margin="4,0,4,8" d:DesignWidth="446" d:DesignHeight="68">
   3:         <Grid.ColumnDefinitions>
   4:             <ColumnDefinition Width="Auto" />
   5:             <ColumnDefinition Width="*" />
   6:         </Grid.ColumnDefinitions>
   7:         <Border VerticalAlignment="Top" Margin="8" Padding="2" Background="White">
   8:             <Image Width="40" Height="40" />
   9:         </Border>
  10:  
  11:         <StackPanel Grid.Column="1" VerticalAlignment="Top" Margin="0,4,0,0">
  12:             <TextBlock x:Name="AuthorName" FontWeight="Bold" />
  13:             <Grid Margin="0,6,0,0">
  14:                 <Grid.RowDefinitions>
  15:                     <RowDefinition Height="Auto" />
  16:                     <RowDefinition Height="2" />
  17:                     <RowDefinition Height="Auto" />
  18:                 </Grid.RowDefinitions>
  19:                 <TextBlock x:Name="TweetMessage" TextWrapping="Wrap" />
  20:                 <TextBlock x:Name="PublishDateLabel" Grid.Row="2"  />
  21:             </Grid>
  22:         </StackPanel>
  23:     </Grid>
  24: </DataTemplate>

I’m also putting the ItemsControl itself into a ScrollViewer since the ItemsControl doesn’t natively provide a scrolling view:

   1: <ScrollViewer Grid.Row="2" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" BorderThickness="1">
   2:         <ItemsControl x:Name="SearchResults" Margin="0,8,0,0" Grid.Row="1" ItemTemplate="{StaticResource SearchResultsTemplate}" />
   3:     </ScrollViewer>

Now all we have is a template, but we have to tell that template what to do with the data it will be receiving.

The XAML binding syntax

Here’s where our binding syntax is going to come in.  You see, ItemsControl is getting data to it (remember we haven’t changed our code so the SearchResults.ItemsSource is still being set to our PagedCollectionView.  To map our model elements to our template we need to use Binding.  The basic XAML binding syntax is:

{Binding Path=<some-data-path>, Mode=<binding mode>}

There are more advanced features you could get into, but this is the basic and we’ll start here.  For instance, to bind our Image element in our template to our Avatar from TwitterSearchResult model, it will look like this:

   1: <Image Width="40" Height="40" Source="{Binding Path=Avatar, Mode=OneWay}" />

And to bind the Author to the AuthorName element like this:

   1: <TextBlock x:Name="AuthorName" FontWeight="Bold" Text="{Binding Path=Author, Mode=OneWay}" />

In both of these we are using OneWay syntax because we don’t need to have it be TwoWay as we aren’t changing data back.  For the PublishDate, we want to provide some explicit formatting of the data.  We can do this through Value Converters.

Building a Value Converter

Value converters are classes that implement IValueConverter, which provides a Convert and ConvertBack methods.  For our PublishDate we’re going to basically allow explicit formatting of the DateTime object.  We’ll create a DateTimeConverter.cs class in a folder in our project called Converters.  The class looks like this:

   1: using System;
   2: using System.Threading;
   3: using System.Windows.Data;
   4:  
   5: namespace TwitterSearchMonitor.Converters
   6: {
   7:     /*
   8:      * Use this converter for formatting dates in XAML databinding
   9:      * Example:
  10:      *  Text="{Binding Path=PublishDate, Converter={StaticResource DateTimeFormatter}, ConverterParameter=MMM yy}" />
  11:      * 
  12:      * */
  13:     public class DateTimeConverter : IValueConverter
  14:     {
  15:         #region IValueConverter Members
  16:  
  17:         public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  18:         {
  19:             DateTime? bindingDate = value as DateTime?;
  20:  
  21:             if (culture == null)
  22:             {
  23:                 culture = Thread.CurrentThread.CurrentUICulture;
  24:             }
  25:  
  26:             if (bindingDate != null)
  27:             {
  28:                 string dateTimeFormat = parameter as string;
  29:                 return bindingDate.Value.ToString(dateTimeFormat, culture);
  30:             }
  31:  
  32:             return string.Empty;
  33:         }
  34:  
  35:         public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  36:         {
  37:             throw new NotImplementedException();
  38:         }
  39:  
  40:         #endregion
  41:     }
  42: }

Now to use this we'll go back to our XAML page that will be using this (Search.xaml) and add an xmlns declaration and a resource.  The xmlns we’ll use looks like this:

   1: xmlns:converters="clr-namespace:TwitterSearchMonitor.Converters"

and then in the Resources section of the XAML (where the other template is defined) we’ll add a resource that points to the converter:

   1: <navigation:Page.Resources>
   2:         <converters:DateTimeConverter x:Key="DateTimeFormatter" />
   3: ...

With these two things in place we can use our converter on our PublishDateLabel element like this:

   1: <TextBlock x:Name="PublishDateLabel" Text="{Binding Path=PublishDate, 
   2:         Converter={StaticResource DateTimeFormatter},
   3:         ConverterParameter=dd-MMM-yyyy hh:mm tt}" Grid.Row="2"  />

This tells XAML that it should run the IValueConverter to get the rendered output.  Our result is the explicit formatting of data that we want.  The result of all this additional syntax for binding now shows the rendering in our desired mockup:

Rendered ItemsControl data template

(yes I know that ‘twitpic’ as a search shows some interesting results…but you can count on it to have fast refreshing data as a search term!)

Great!  That wasn’t that difficult, was it?  This binding syntax will be essential to building applications for you.

Storing some settings and configuration data

One of the things that would be helpful for our application is to store the last tweet ID so that the next time the application is run, we can start where we left off without starting over.  Additionally it would be cool to save the search term history so that we can view it in our History navigation point later.

To accomplish this, we’ll be using Isolated Storage available in Silverlight.  Isolated Storage enables a low-trust user-specific location for storing simple data.  For some more information on Isolated Storage:

To do this I’m going to add a Helper class to our Model folder.  This helper class will assist us in saving/reading data from our isolated storage location.  The basics of IsolatedStorage are that you create a file to which you can read data from or write data to if you want.  In our use we’ll use IsolatedStorageSettings for saving simple name/value pair data (search term/last ID).  Here’s the contents of the Helper.cs class:

   1: using System.IO.IsolatedStorage;
   2:  
   3: namespace TwitterSearchMonitor.Model
   4: {
   5:     public class Helper
   6:     {
   7:         internal static string GetLatestTweetId(string searchTerm)
   8:         {
   9:             if (IsolatedStorageSettings.ApplicationSettings.Contains(searchTerm))
  10:             {
  11:                 return IsolatedStorageSettings.ApplicationSettings[searchTerm].ToString();
  12:             }
  13:             else
  14:             {
  15:                 return "0";
  16:             }
  17:         }
  18:  
  19:         internal static void SaveLatestTweetId(string searchTerm, string latestId)
  20:         {
  21:             if (IsolatedStorageSettings.ApplicationSettings.Contains(searchTerm))
  22:             {
  23:                 IsolatedStorageSettings.ApplicationSettings[searchTerm] = latestId;
  24:             }
  25:             else
  26:             {
  27:                 IsolatedStorageSettings.ApplicationSettings.Add(searchTerm, latestId);
  28:             }
  29:         }
  30:     }
  31: }

Now in our Search.xaml.cs we’ll add the following in SearchForTweetsEx after the activity indicator is set:

   1: _lastId = Helper.GetLatestTweetId(SearchTerm.Text); // get the latest ID from settings
   2:  
   3: Helper.SaveLatestTweetId(SearchTerm.Text, _lastId); // saving for history even if a result isn't found

and then in the OnReadCompleted after we close the XmlReader we’ll add this:

   1: Helper.SaveLatestTweetId(SearchTerm.Text, _lastId); //saving last tweet id

And that now saves the search terms used as well as the last ID found if a result was found.

Summary

In this step we’ve set up a data template for a control, used some simple data binding using the XAML declarative syntax, added a value converter to format our view of information and save settings information to a local storage mechanism.

We’ve got basically our application working, so let’s start adding some interesting polish to the UI.

Let’s move on to part 5 where we add some new controls to enhance the experience using the data we just stored in this step.


This work is licensed under a Creative Commons Attribution By license.

| Comments

I got an email the other day about if there was a way to pass an object between the navigation pages in Silverlight 3.  The scenario was that the developer wanted to use the same data, but represent it visually in different ways.

Silverlight 3 introduces a new navigation framework in the runtime making it easier to navigate to different areas of an application and assist in ‘deep linking’ concepts for applications.  More resources:

At first my reaction was “no, we don’t allow that easily” but then I thought about it a bit and played around with a sample in the context of this developer’s use case.  Right now, the way you can quickly pass chunks of data to another page is via query string mechanisms.  So in my code I can say:

   1: myFrame.Navigate(new Uri("/foo.xaml?customerId=1234", UriKind.Relative));

And then in the navigated page something like:

   1: string customerId = this.NavigationContext.QueryString["customerid"];

This works fine for string/simple data.  In fact I could probably serialize a simple type and send it this way as well…but I don’t think that was the desired intent of this developer.  But if you think about the concept of the Frame, then you can start thinking about DataBinding techniques and how we can use the Frame as our container.  Allow me to think out loud…

Let’s use the default Silverlight Navigation Application template in the Silverlight 3 Tools for Visual Studio.  This will give us enough stub to work with.  If you look at MainPage.xaml you’ll see that the page has one Frame element in it:

   1: <navigation:Frame x:Name="Frame" Source="/Views/HomePage.xaml"
   2:       HorizontalContentAlignment="Stretch"
   3:       VerticalContentAlignment="Stretch"
   4:       Padding="15,10,15,10"
   5:       Background="White"/>

This is the core element that is going to receive navigation commands and change its content based on those commands.  Now in the Loaded event handler of MainPage, let’s grab some data.  I’m using a simple class here that just iterates a Person type (mainly so I can include it in the sample easily).  My Loaded event handler now looks like this:

   1: void MainPage_Loaded(object sender, RoutedEventArgs e)
   2: {
   3:     People p = new People();
   4:     List<Person> peeps = p.GetPeople();
   5:  
   6:     this.Frame.DataContext = peeps;
   7: }

So you can see that I’m now setting the DataContext of the Frame element to my List<Person>.  So now let’s crack open some of the other pages.  Again, remember the scenario: same data, different views.  Open the Views/HomePage.xaml and let’s show a view of just a simple list of names.  I added a ListBox and just displayed the FullName property of my data:

   1: <StackPanel> 
   2:     <TextBlock Text="Name List" Style="{StaticResource HeaderTextStyle}"/>
   3:     <StackPanel Style="{StaticResource ContentTextPanelStyle}">
   4:         <ListBox x:Name="PeopleList" DisplayMemberPath="FullName" 
   5:             ItemsSource="{Binding}" />
   6:     </StackPanel>
   7: </StackPanel>

Notice that there is going to be no code here in the source file for HomePage.xaml.cs – we are using the {Binding} property for the ItemsSource…essentially trickling down the DataContext from the Frame.  Remember, that HomePage.xaml is essentially a child control of the Frame so it is aware of the DataContext.  Now let’s go into AboutPage.xaml for our more detailed view, showing a DataGrid of all the elements of the data:

   1: <StackPanel>
   2:     <TextBlock Text="Detail" Style="{StaticResource HeaderTextStyle}"/>
   3:     <TextBlock Text="Detail list of members with gender." 
   4:             Style="{StaticResource ContentTextStyle}"/>
   5:     <data:DataGrid ItemsSource="{Binding}"/>
   6: </StackPanel>

Again, no code here to retrieve the data or wire it up – using {Binding} to the DataContext again.  So now with one data fetch and binding to our navigation context (Frame) we can re-use that same object across different views and the result shows us different levels of detail.

View 1: simple listView 2: detail list

So at least that is one thought of how to share the information.  What do you think?  Obviously it will not work in all scenarios, but also remember you can have more than one navigation frame in your application too!  Here’s the sample code for these thoughts: SilverlightApplication32.zip

Hope this helps!

| Comments

If you are working with Silverlight and data you most likely are going to leverage data binding at some point and run into some needs to format the data in the XAML.  Luckily this can be done using value converters, which have been available for WPF since it’s inception as well.  Let’s explore what I’m talking about using a common formatting need: dates.

Consider this list box output binding:

   1: <ListBox x:Name="FeedList">
   2:     <ListBox.ItemTemplate>
   3:         <DataTemplate>
   4:             <StackPanel Orientation="Vertical">
   5:                 <TextBlock FontFamily="Arial" FontWeight="Bold" Foreground="Red" Text="{Binding Title.Text}" />
   6:                 <TextBlock FontFamily="Arial" Text="{Binding PublishDate}" />
   7:             </StackPanel>
   8:         </DataTemplate>
   9:     </ListBox.ItemTemplate>
  10: </ListBox>

Assume this XAML binds to SyndicationFeed.Items data coming from an RSS feed.  If we simply bind it the result would be this:

Maybe we don’t want our date to be formatted in such ‘system’ looking format and we want something like “July 16.”  Enter the IValueConverter class.  First we’ll add a class to our Silverlight application, let’s call it Formatter.  Once we add that class we need to implement the IValueConverter interface which gives us Convert and ConvertBack functions we have to implement:

   1: public class Formatter : IValueConverter
   2: {
   3:     #region IValueConverter Members
   4:  
   5:     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
   6:     {
   7:         throw new NotImplementedException();
   8:     }
   9:  
  10:     public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  11:     {
  12:         throw new NotImplementedException();
  13:     }
  14:  
  15:     #endregion
  16: }

You can see that the Convert function gets some good information that we can use to do the conversion.  The parameter value is the formatter passed into the argument.  For example in our desire to display “July 16” we want to use the date formatter shortcut of “M” for the parameter.  Let’s start the conversion.

   1: public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
   2: {
   3:     if (parameter != null)
   4:     {
   5:         string formatterString = parameter.ToString();
   6:  
   7:         if (!string.IsNullOrEmpty(formatterString))
   8:         {
   9:             return string.Format(culture, formatterString, value);
  10:         }
  11:     }
  12:  
  13:     return value.ToString();
  14: }

What we are doing here is ensuring that a parameter is passed in and then using the String object to handle the formatting for us.  Great, now we have our Convert function (in this sample we are doing one-way binding so I’m going to leave ConvertBack alone for now).  Let’s compile our code and then move back to the XAML.  In XAML we now want to make our converter available for use.  The first step is to add the CLR namespace to our root XAML node:

   1: xmlns:converter="clr-namespace:TypeConverter_CS"

The next step is to add our converter class as a resource to our XAML control so that we can use it throughout the control later:

   1: <UserControl.Resources>
   2:     <converter:Formatter x:Key="FormatConverter" />
   3: </UserControl.Resources>

Now if we go back to our XAML where we are data binding the date we can implement this and pass in the converter parameter (format) we want to use.  The end result full XAML looks like this:

   1: <UserControl x:Class="TypeConverter_CS.Page"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     xmlns:converter="clr-namespace:TypeConverter_CS"
   5:     Width="400" Height="300">
   6:     <UserControl.Resources>
   7:         <converter:Formatter x:Key="FormatConverter" />
   8:     </UserControl.Resources>
   9:     <Grid x:Name="LayoutRoot" Background="White">
  10:         <ListBox x:Name="FeedList">
  11:             <ListBox.ItemTemplate>
  12:                 <DataTemplate>
  13:                     <StackPanel Orientation="Vertical">
  14:                         <TextBlock FontFamily="Arial" FontWeight="Bold" Foreground="Red" Text="{Binding Title.Text}" />
  15:                         <TextBlock FontFamily="Arial" Text="{Binding PublishDate, Converter={StaticResource FormatConverter}, ConverterParameter=\{0:M\}}" />
  16:                     </StackPanel>
  17:                 </DataTemplate>
  18:             </ListBox.ItemTemplate>
  19:         </ListBox>
  20:     </Grid>
  21: </UserControl>

Notice how we made a reference to our StaticResource (using the key name we provided) and then passed in the ConverterParameter of {0:M} to format our date.  The resulting output is now:

And you’ll notice the date formatting.  Now in our converter we could have been real explicit in our Convert function and looked for a date and converted it specifically, but our converter code is generic enough that it can handle some other input types like more complex date formats or numbers.  If we used this same converter code on a number we could pass in the ConverterParameter of {0:c} for currency formatted information.

If you use Expression Blend as well, you can also use some of the user interface properties to specify the binding values that will get output as XAML…here’s a screenshot of the converter settings UI in blend:

This method is useful when you may have custom conversion needs for your data.  Hope this helps!  You can download this sample here: TypeConverter_CS.zip

| Comments

Very cool think popped in my RSS reader this morning.  Scott Guthrie (now a corp VP, congrats Scott) put up a first look post at Silverlight 2.  Not just a 'here's what is coming' but an 8-part tutorial as well as he built a sample application trying to leverage and demonstrate various parts of Silverlight 2.

These tutorials should be extremely helpful for those wanting to understand some of the newer concepts brought to Silverlight.  If you haven't done a lot (or any) WPF coding before, some of this should jumpstart your knowledge a bit.

take a look at 'First Look at Silverlight 2.'