UPDATED: If you found this post via a search, the below information was for Silverlight 3 beta and no longer works in Silverlight 3 release.  Click here for an updated tutorial on grouping in the Silverlight DataGrid for Silverlight 3.

I got this question on how do you add grouping to the DataGrid in Silverlight without using the RIA Services ObjectDataSource.  Frankly I didn’t know off the top of my head either and I’ve since learned it isn’t obvious.  Allow me to explain the steps.

In my simple app I have a static class that supplies some hard-coded data:

   1: public List<Person> GetPeople()
   2: {
   3:     List<Person> peeps = new List<Person>();
   4:     peeps.Add(new Person() { FirstName = "Tim", LastName="Heuer", Gender="M", AgeGroup="Adult" });
   5:     peeps.Add(new Person() { FirstName = "Lisa", LastName="Heuer", Gender="F", AgeGroup="Adult" });
   6:     peeps.Add(new Person() { FirstName = "Zoe", LastName = "Heuer", Gender="F", AgeGroup="Kid" });
   7:     peeps.Add(new Person() { FirstName = "Zane", LastName = "Heuer", Gender="M", AgeGroup="Kid" });
   8:     return peeps;
   9: }

You can see there is a Gender field and I want to list them grouped on that in a DataGrid.  So I would first add a reference to the DataGrid control library and add that:

   1: <navigation:Page x:Class="SilverlightApplication32.AboutPage" 
   2:            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   3:            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
   4:            xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
   5:            xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
   6:            Title="AboutPage Page">
   7:     <Grid x:Name="LayoutRoot" Background="White">
   8:         <StackPanel>
   9:             <TextBlock Text="Detail" Style="{StaticResource HeaderTextStyle}"/>
  10:             <TextBlock Text="Detail list of members with gender." Style="{StaticResource ContentTextStyle}"/>
  11:             <data:DataGrid ItemsSource="{Binding}"/>
  12:         </StackPanel>
  13:     </Grid>
  14: </navigation:Page>

Notice the xmlns attribute in the control (this is in a navigation page, but the syntax is the same).  Now how to add the grouping?  You’d hope it would be something as simple as GroupPathName on the DataGrid or something.  But remember that grouping can be done multilevel.  So to add grouping we have to do some things first.  First, add a reference to System.ComponentModel in your application.  Then add another xmlns to your control for the library, since that is where the PropertyGroupDescription is located.  The result is that we have:

   1: <navigation:Page x:Class="SilverlightApplication32.AboutPage" 
   2:            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   3:            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
   4:            xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
   5:            xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
   6:            xmlns:cm="clr-namespace:System.Windows.Data;assembly=System.ComponentModel"
   7:            Title="AboutPage Page">
   8:     <Grid x:Name="LayoutRoot" Background="White">
   9:         <StackPanel>
  10:             <TextBlock Text="Detail" Style="{StaticResource HeaderTextStyle}"/>
  11:             <TextBlock Text="Detail list of members with gender." Style="{StaticResource ContentTextStyle}"/>
  12:             <data:DataGrid ItemsSource="{Binding}">
  13:                 <data:DataGrid.GroupDescriptions>
  14:                     <cm:PropertyGroupDescription PropertyName="Gender" />
  15:                 </data:DataGrid.GroupDescriptions>
  16:             </data:DataGrid>
  17:         </StackPanel>
  18:     </Grid>
  19: </navigation:Page>

Notice the ComponentModel use within the DataGrid’s GroupDescriptions node.  This would render in a UI like:

DataGrid single grouping

Want to add multilevel grouping? Just add another PropertyGroupDescription:

   1: <data:DataGrid ItemsSource="{Binding}">
   2:     <data:DataGrid.GroupDescriptions>
   3:         <cm:PropertyGroupDescription PropertyName="Gender" />
   4:         <cm:PropertyGroupDescription PropertyName="AgeGroup" />
   5:     </data:DataGrid.GroupDescriptions>
   6: </data:DataGrid>

And it will render top-down:

DataGrid multilevel grouping

You can also do this in code of course like this (assuming the DataGrid is named “MyGrid”:

   1: MyGrid.GroupDescriptions.Add(new PropertyGroupDescription("Gender"));

I found this information on one of our tester’s site, Naga Satish.  Naga also has some other valuable DataGrid information:

I recommend you bookmark a few :-).

All your base are belong to us.

The year was nineteen ninety something.  A strapping young chap entered the world of technology.  With overpromises from tech leads, undertrained programmers, and caffeine, there was nothing we couldn’t conquer. 

Or something like that.

I’ve pretty much been in technology all my “professional” life…save it being a small sting of leadership consulting right out of college that a totaled car at Duquesne solved that decision for me….but that’s another story.  I’ve grown up around programming, I’ve programmed like the worst of them and I am a better person for ‘thinking aloud’ and learning what others are doing to make me better.

Over the past 2 years I, like many of you, have entered in the world of what seems to be called “social media” or “new media.”  No, I’m not about to claim I’m one of them (warning may be NSFW with language).  But I will say I’m a user, dare I say a power user.  I didn’t get on the MySpace train because at the time I just didn’t get it and it didn’t look tailored for me.  I gave up my Geocities account long ago and didn’t feel the need to start a new one with MySpace :-).  I joke, as I know it is valuable for some social circles, just not mine…some pages make my eyes bleed.

Enter Facebook.  I list my LinkedIn account in my contact information, but I’ll be honest with you – I don’t use it.  I also stopped using Plaxo as a result of company IT restraints.  So apologies to all you Plaxo Pulse invitations…I’m not responding to them.  All of these networks seem to share the currency of “friends” in their taxonomy.  It got out of control fast on Facebook for me with tons (well relatively speaking of course) started sending friend requests.  Are these really my friends? I had to ask myself this.  But being the people-pleaser I think I am and not wanting to offend most I just started accepting them all.  Thus, my Facebook friends have gotten out of control.

Enter Twitter.  This gave us all an outlet to strip down to “status” updates.  I signed up immediately and thought it was lame.  What possible use could this be for me?  Of course I was wrong and it has been the single-most useful social tool I leverage.  I use it daily and treat it just like what I think it is – a conversation I can enter/leave/comment on at any time.  There is a friend (follower) concept, but it is easier to deal with because people can choose to follow me if I’m public (more on that later).  And I can choose who I want to follow and there doesn’t have to be a mutual connection of permission between the two.  I like that.

Enter my wife.  She’s a wonderful woman.  She’s super smart and super talented.  For years she’s made fun of my geekiness.  For a while I was McGeeky to her friends.  She would mock me in her speak (she still does sometimes).  But then something changed.  A genuine interest in certain things.  It started with her retiring from her job.  She still wanted to be connected, so got a laptop.  I introduced her to GMail.  Later she started asking what’s this blog stuff?  Soon enough she started a blog – more for journaling our family life and her perspective on it with parenting, etc.  Her blogging has exploded.  She has more posts than me combined over the 6 years I’ve been blogging.  It’s frightening and fun at the same time.  I love to see her spunky personality come through in her writing.  Then came Facebook.  Then came Twitter.

Fast forward to a few weeks ago.  We were on date night and started talking about all this stuff.  It was a surreal moment that my wife would actually want to talk about tech stuff.  You see, she has become a power Twitter user among her friends.  Her Blackberry probably sparked a lot of this with text messaging with her friends and now she also uses Twitter via her mobile!  She signed up, they signed up and she’s really using it a lot.  For now for just fun stuff, but I see her use grow more…as does her followers.  She even took a web seminar about how to use Twitter effectively.  In this conversation she asked me what’s the point for Facebook if I have Twitter?  Good question.  It was good timing as well because on that day Seesmic released their Facebook desktop application which did one thing – essentially boil Facebook down to a status stream.  As we talked about this I realized that my use of Facebook was tiny.  Beyond looking at a friend you hadn’t seen in a while and then checking out their pictures, my use boiled down to the status stream.  It was an interesting conversation we had that night.  And weird.

Since then my wife has been opening my eyes to some things.  I kept seeing these tweets of I’ve listed myself in localtweeps.com under zip code XXXX.  So me being part of the nerd sheep, I added myself.  Then I got a lesson in privacy from my wife.  She convinced me in less than a minute that wasn’t a good idea.  Again, we had a good conversation about it.  She even pointed out that people who block their Twitter stream but post it to Facebook via the linking, aren’t really blocking anything.  I actually didn’t even make the obvious connection.

Now within the past week she’s asked me about tools and I believe she started using Twhirl.  Her latest tweet had a TwitPic URL in it. 

WHAT HAVE I CREATED!?

Seriously it is fun and bazaar at the same time.  I love to see my wife blogging, twittering, and bringing technology into her life.  Some of it concerns me, but I can’t judge…my thoughts are pretty much an open book on the web.  So why am I writing all this and wasting precious whitespace on the interwebs?  Who knows…but just thoughts I had as my worlds have converged a bit.  It reminds me of a Seinfeld episode where Jerry and Elaine contemplate inviting George’s girlfriend on an outing.  Kramer points out:

Jerry, don't you see? This world here, this is George's sanctuary. If Susan comes into contact with this world, his worlds collide. You know what happens then? (Kramer raises his hands into the air and slowly brings them together in an explosion.) – from “The Pool Guy” episode

It’s like Relationship George and Independent George.  Except for me it is Husband Tim and Geek Tim.  Worlds colliding my friend, worlds colliding.

Are you a startup organization?  Perhaps your the next greatest Silverlight control vendor or have a great app?  I want to help.  If you’re a Silverlight startup (or any startup really for that matter), reach out to me.  If you haven’t heard of BizSpark yet, you’re potentially missing out.

If you meet the following criteria:

  • privately held company
  • in business less than 3 years
  • generate less than USD $1 million in revenue

you may qualify to get access to production licenses for development tools, platform products and server licenses for immediate use.  Take advantage of this and the Web Platform Installer to jumpstart your biz.  Read the details about BizSpark here: How BizSpark Works.

I’m one of the BizSpark Champs and want to help our startups out there – no matter what you are doing – be successful quickly.  Obviously I’d love to see some Silverlight/RIA goodness, so if you’re in that camp, be sure to let me know!  You can reach out to me via my contact information to start a dialogue.

I’ve been playing around with the Silverlight 3 navigation framework some more (thanks for the comments/thoughts on the last post about sharing data).  I got a few emails about understanding how the navigation works and people coming up with interesting uses.  Let’s take a moment to explore two of these concepts: out-of-browser navigation and controlling your navigation in your app.

Navigation Basics

If you are using Visual Studio 2008 and the Silverlight 3 tools, you’ll notice that when you choose to create a new project (or perhaps you didn’t notice and this will be new to you) that you have an option to create a Silverlight Navigation Application which is a starter template for some basic navigation framework.  This isn’t required to use the navigation framework, but merely a starting point.

Silverlight Navigation Application template

Once you have this template and click on the different navigation buttons (and/or add your own as well) you’ll see that the content changes based on the event.  Additionally you should notice that the browser’s back/forward buttons integrate with this functionality and allow you to navigate back/forward using the browser controls as well, honoring the navigation context of the application.

Out-of-browser Navigation

So now you’ve finished your app, complete with navigation and also added the functionality to allow the application to be installed out-of-browser.  Yipee!  Your users install the application offline and boom, they call you and say “how do I go back to where I was?”  Well, ideally you’ve created an application that has good navigation points in it for them, but perhaps you want to add simple forward/back functionality while in out-of-browser mode similar to the in-browser buttons that come with their preferred Internet browsing software.

Guess what?  The navigation framework provides some APIs to help you that are a part of the Frame that you are navigating:

  • CanGoForward/CanGoBack
  • GoForward/GoBack

With these two you can emulate the same browser back/forward functionality.  Here’s an example using the default VS2008 navigation template.  In MainPage.xaml I’ve removed the branding information (your.application.name) and added the following (about line 30):

   1: <StackPanel Style="{StaticResource BrandingPanelStyle}" x:Name="JournalNav">
   2:     <Button Content="back" Style="{StaticResource PageLinkStyle}"
   3:         x:Name="NavBack" Click="NavBack_Click" />
   4:     <Button Content="forward" Style="{StaticResource PageLinkStyle}" 
   5:         x:Name="NavFwd" Click="NavFwd_Click" />
   6: </StackPanel>

The NavBack/NavFwd click functions look like this:

   1: private void NavBack_Click(object sender, RoutedEventArgs e)
   2: {
   3:     this.Frame.GoBack();
   4: }
   5:  
   6: private void NavFwd_Click(object sender, RoutedEventArgs e)
   7: {
   8:     this.Frame.GoForward();
   9: }

Now on the Frame that I’m using I added an event handler for Navigated that looks like this:

   1: private void Frame_Navigated(object sender, NavigationEventArgs e)
   2: {
   3:     NavBack.Opacity = Frame.CanGoBack ? 1 : 0;
   4:     NavFwd.Opacity = Frame.CanGoForward ? 1:0;
   5: }

And finally I’ve added a Loaded event handler to MainPage to handle the initial load:

   1: void MainPage_Loaded(object sender, RoutedEventArgs e)
   2: {
   3:     JournalNav.Visibility = App.Current.RunningOffline ? Visibility.Visible : Visibility.Collapsed;
   4: }

The end result is the application in-browser works fine and uses the browser software back/forward buttons.  When installed out-of-browser, you’ll notice that an application-specific “back” and “forward” links are created (only when they are applicable) and the user can still navigate the frame that way.

In browser:

Navigation in-browser

Out-of-browser:

Navigation out-of-browser

Simple enough and I would not have had to change anything about how I already used the navigation framework in my application.

Controlling your navigation history

The other comment I’ve got is if people wanted to have ultimate control over their history navigation and have some parts integrate with the browser and other parts not.  Let me introduce you to a property of Frame: JournalOwnership.  By default the setting is Automatic, which means that the frame integrates with the browser history journal.  Setting it to something else, like OwnsJournal for example, means that it will not automatically integrate and you are now responsible for that navigation. 

What this means is that you can have a frame that is independent of the browser navigation, but still leverage the power of the framework.  Let’s alter our default template and add one of our navigation pages to include it’s own navigation pages, but those we don’t want to be a part of the overall app. 

I’ve modified the MainPage to add a link to another page called SubNavigation.xaml which then looks like this:

   1: <StackPanel>
   2:     <StackPanel x:Name="JournalNav" Orientation="Horizontal">
   3:  
   4:         <Button Click="NavButton_Click" Tag="/Views/SubNav/SubNav1.xaml" Content="section 1" 
   5:                     Style="{StaticResource PageLinkStyle}"/>
   6:         <Button Click="NavButton_Click" Tag="/Views/SubNav/SubNav2.xaml" Content="section 2" 
   7:                     Style="{StaticResource PageLinkStyle}"/>
   8:  
   9:         <Button Content="back" Style="{StaticResource PageLinkStyle}" 
  10:             x:Name="NavBack" Click="NavBack_Click" />
  11:         <Button Content="forward" Style="{StaticResource PageLinkStyle}" 
  12:             x:Name="NavFwd" Click="NavFwd_Click" />
  13:     </StackPanel>
  14:     <navigation:Frame x:Name="SubFrame" JournalOwnership="OwnsJournal"
  15:             HorizontalContentAlignment="Stretch" Source="/Views/SubNav/SubNav1.xaml"
  16:                           VerticalContentAlignment="Stretch"
  17:                           Padding="15,10,15,10"
  18:                           Background="White"/>
  19: </StackPanel>

You’ll see it looks similar (just for demonstration purposes) and includes a Frame.  Notice the JournalOwnership property set to OwnsJournal.  Now I also have the same back/fwd links  and functions to control them (GoBack/GoForward) in this sample, but now since I (well, SubFrame) owns the journal, I’m responsible for the navigation.  So here’s what happens:

  • User navigates to app
  • User clicks “about” – browser history appended
  • User clicks “sub navigation” – browser history appended
  • Within the “sub navigation” page, user clicks “subnav 2” – browser history not updated
  • User clicks “back” within the “subnav 2” page – user is taken back to “subnav 1”

So By changing the JournalOwnership, I get the control to manage the journal navigation, but also have to remember that.

Summary

I hope these two little experiments help you look at the navigation feature in some new ways.  It’s really a great feature I’m having fun thinking about things out loud with you all and getting feedback and more ideas.  I can’t wait to see great Silverlight 3 applications built with our framework!

The code that I used for these experiments is available here: slnavexperiments1.zip.  You will need the Silverlight 3 developer tools to run this code.  You can obtain all those tools here at the Silverlight 3 beta information section.

Hope this helps!

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!