Monthly Archive for March, 2006

Ontela Outed

Dan and Brian’s company has been outed by the Seattle PI. I hope they’re ready for the ensuing fame and fortune!

The WPF/E Team is Blogging

WPF/E, or “Windows Presentation Foundation Everywhere,” is a lightweight cross-platform (and cross-browser) runtime whose functionality is a subset of WPF. Joe Stegman and Mike Harsh are Program Managers on the WPF/E team, and both of them have just started blogging about the work they are doing. Check ‘em out!

Implementing Tabbed Browsing Using Island Frame

In my last post, I introduced a WPF feature that we affectionately call “Island Frame” (an Island Frame is actually a Frame which has Frame.JournalOwnership = JournalOwnership.OwnsJournal). One of my favorite applications of this feature is that it is now very easy to build UI that uses a tabbed navigation model.

Tabbed browsing using 3 Island Frames

The basic XAML for this is as follows:

<Window x:Class="BeautifulIsland.Window1"
    xmlns=
    "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Tabbed Browsing Sample"
    Height="400"
    Width="500"
    >
  <TabControl>
    <TabItem>
      <TabItem.Header>
      <Binding ElementName="TabFrame1" Path="Content.Title" />
      </TabItem.Header>
      <Frame Name="TabFrame1" JournalOwnership="OwnsJournal"
            Source="page1.xaml" />
    </TabItem>
    <TabItem>
      <TabItem.Header>
        <Binding ElementName="TabFrame2" Path="Content.Title" />
      </TabItem.Header>
      <Frame Name="TabFrame2" JournalOwnership="OwnsJournal"
           Source="page2.xaml" />
    </TabItem>
    <TabItem>
      <TabItem.Header>
        <Binding ElementName="TabFrame3" Path="Content.Title" />
      </TabItem.Header>
      <Frame Name="TabFrame3" JournalOwnership="OwnsJournal"
            Source="page3.xaml" />
    </TabItem>
  </TabControl>
</Window>

The notable parts of this XAML are as follows:

  • I have a TabControl with three TabItems, each of whose only child is a Frame.
  • For each Frame, I have set JournalOwnership = JournalOwnership.OwnsJournal.
  • I did not need to set NavigationUIVisibility because the default value is “Automatic”, which means that navigation UI will be shown if the Frame has its own Journal, and will not be shown if it doesn’t.
  • I used databinding to bind the TabItem.Header property to the title of the Page hosted in the Frame.

Obviously this sample is simplified. In a real tabbed browsing application, you would want to provide a mechanism for creating new tabs and opening content in those tabs. But that’s the easy part. :)

You can download the source for this sample here. It works on the February CTP.

“Island Frame”

You may have noticed in the past that the WPF Frame element didn’t work very well when hosted in a Window (it worked just fine in a NavigationWindow or in a Page hosted in the browser). The Frame could navigate to content, but there was no way to navigate forward or back, as you could do with a Frame hosted in a NavigationWindow. This wasn’t just because there was no navigation UI associated with the Frame, but because the Frame had no Journal of its own; that is, there was no bookkeeping mechanism to record the navigations.

The reason that Frame didn’t have a Journal is somewhat historical — WPF Frames don’t have their own Journals because HTML frames don’t have their own travel logs. In HTML, a frame’s navigation history is recorded by the travel log associated with the top-level page. That is why clicking on the back and forward buttons on the browser may cause either the top-level browser window or a frame to navigate — it depends on what is at the top of the travel log’s “back stack”. WPF Frames work the same way for consistency, and in most cases, this is the behavior people want.

But there were a few holes in this story. In particular:

  • What if you wanted to host a Frame inside a (non-navigation) Window, to provide a region of navigable content on a page?
  • What if you wanted to have Frames whose navigation was independent of the top-level navigation container?

The answer to both of these questions was the same: roll your own. And rolling your own wasn’t easy.

To address this, we added a new property to Frame that enables Frame to have its own Journal. The property is called JournalOwnership, and there is a JournalOwnership enum with three values: Automatic, OwnsJournal, and UsesParentJournal. These properties behave as follows:

  • Automatic - Whether or not this Frame has its own Journal depends on its parent. If the Frame is hosted by a Frame or NavigationWindow, it behaves as though UsesParentJournal was set. If it is not hosted by a Frame or NavigationWindow, it behaves as though OwnsJournal was set.
  • OwnsJournal - The Frame has its own Journal which operates independent of the hosting navigator’s Journal (if it has one).
  • UsesParentJournal - The Frame’s JournalEntries are merged into the hosting navigator’s Journal. If the hosting navigator does not have a Journal, then no journaling occurs for this Frame.

Around here, we started affectionately calling a Frame that has its own Journal an “Island Frame”. The name stuck, and now everyone on my team uses it (and it’s much easier than saying “a Frame that has Frame.JournalOwnership=JournalOwnership.OwnsJournal”).

The other detail that falls out of providing this property is that you may want to provide some navigation UI on an independent Frame, to control the navigations that occur inside that Frame. For this, we added a NavigationUIVisibility property on Frame, whose default value will show navigation UI if the Frame has its own Journal, and will not show navigation UI if the Frame shares a Journal with a parent navigator.

If this all sounds somewhat obscure and theoretical, hopefully my next post (a cool application of Island Frames) will help illuminate the possibilities a little better…

A Revolutionary Evening

Tonight when Kenny and I got home, we noticed that our downstairs neighbors’ cars were both gone. We looked at each other, and then ran upstairs: when the neighbors are gone, it’s Dance Dance Revolution time!

Unfortunately, the neighbors are rarely gone, so we basically both still really suck at DDR. After about 30 minutes, we were beat.

But then later this evening, Vidya called to see if we were around and wanted to play Karaoke Revolution. So now she’s here and we’re singing. It’s been a revolutionary evening.

And Kenny just found out about Karaoke Party, which has a duet mode, and integrates with DDR so you can sing and dance at the same time!