Clearification

My friend and co-worker Hamid just pointed me to Clearification.com, a very interesting new joint project from the Windows Vista team and Demetri Martin. It hosts a series of episodes that tell the story of Demetri’s “condition,” and presumably how he overcomes it. Only the first episode is available now, but the others are all “coming soon.” The site publishes a feed so that you can keep up to date on new additions, and of course, so that you can watch those new episodes as soon as they are posted. It seems pretty cool so far, I’d definitely recommend checking it out.

Architects Blogging Like Crazy

Two of our architects, Mike Hillberg and Rob Relyea, blogged up a storm while I was gone. There is a great wealth of information on both of their blogs, and I am learning a lot about WPF by reading them. I’m especially impressed that Mike has only been blogging for 12 days and has already contributed an incredible amount of information to the WPF blogosphere. And I really like Rob’s new periodic round-up of WPF news and blog articles. It’s good stuff, check it out!

I guess we really have transitioned into ship mode if our architects have this much time to blog. :)

No HW Acceleration for Layered Windows on XP

While I was on vacation, Seema blogged that WPF will not have hardware acceleration for layered windows on Windows XP. Nick elaborates a bit to explain that while we did once have partial support for this, it was unreliable and sometimes slower than software rendering. Rest assured that hardware acceleration is still there for Vista. If you have any questions, Seema is the expert.

How Controls Retain Their State when You Navigate Away

Over on Bea’s excellent blog, Sam asked a great question about how controls retain their state when you navigate away from a page:

This got nothing to do with threads, sorry for intruding, but I don’t know where to ask this question (managed newsgroups provide no answer)

When you navigate back in a browser-like WPF application, the pages are re-created (at least the constructor is called).

And somehow, magically, the content for Textbox(es) in the page will be filled with whatever had been in there when the page had been left.

Since the page is created anew on navigating ‘Back’, where does this content come from? Is it bound to some kind of session storage as default?

And how do I get my own values back (as content for Listboxes for example are lost on navigating)?

thanks, Sam!

First of all, Sam, I am sorry that no one answered your newsgroup question. I just returned from a long vacation and I hope that this delayed response is still helpful.

Understanding how control state is retained requires a bit of knowledge of how “journaling” works. Journaling is the mechanism for keeping track of the user’s navigation history – the “Journal” is an internal data structure which consists, among other things, of a ForwardStack and BackStack (these stacks are exposed on Frame and NavigationWindow). As a user navigates through a set of pages (say by clicking on Hyperlinks that point to other pages), JournalEntries are added to the BackStack. Specifically, a BackStack entry for a page is added upon navigating away from the page. If the user clicks on the back button, a few things happen: a JournalEntry is popped off the BackStack, the page it represents is rehydrated, the framework navigates to the rehydrated page, and a JournalEntry for the current page is created and added to the ForwardStack. If a user initiates a new navigation, the forward stack is cleared.

This system is modeled after how navigation works in all popular web browsers today, and you will notice that WPF navigation works the same way that navigation works in Internet Explorer, for example.

There are two main ways that JournalEntries are created, depending on what is being journaled (and also on the value of the KeepAlive property, which I will discuss in a moment):

  1. By URI: If you navigate to a XAML page via its source URI (e.g. page1.xaml), and then navigate away from it, the page is stored simply by creating a new JournalEntry that stores the URI for that page (the JournalEntry.Source property is used for this purpose). Navigating back to the page simply requires the framework to get the Source and navigate to it.
  2. By object: If you navigate to an object rather than a XAML page (e.g. by creating an object tree programmatically and calling Navigate(object content)), and then navigate away from it, we cannot journal by URI because there is no URI (!). In this case, the object tree is kept alive and a reference to the tree is stored in its JournalEntry. Navigating back to the page involves re-attaching the saved tree as the Content of the Frame or NavigationWindow.

The default behavior for journaling pages that have URIs is by URI, but this can be overridden by setting JournalEntry.KeepAlive (which is an attached DP) if desired. Keep in mind that there are working set implications when you use KeepAlive, because the whole page really is kept alive in memory. URI JournalEntries are, of course, smaller.

At this point, it is probably obvious to you that when we journal “by object,” storing the user-modified state of controls (like TextBoxes and RadioButtons) is trivial: because the whole tree is kept alive, there is no additional work to do. When we journal by URI, we traverse the tree and look for controls that have properties which should be journaled. We store these property values in the JournalEntry along with the source URI for the page. We know which properties should be journaled because they have set the FrameworkPropertyMetadataOptions.Journal flag. Also note that we will ignore controls which do not have the PersistId property set. When a page is rehydrated from a JournalEntry, we navigate to the JournalEntry.Source URI and we apply all of the deltas to control state that we have stored in the Journal.

In general, controls whose state may be changed via user interaction maintain their state across navigations (there are notable exceptions, like PasswordBox). When authoring custom controls, you should consider whether or not your controls have state that may be modified via user interaction, and if they can, then you should usually mark those properties with FrameworkPropertyMetadataOptions.Journal and set the PersistId. If your control stores sensitive data like a password or credit card number, you will likely not want that state to be journaled.

Sam, I did not understand the last part of your question, about ListBox. Could you elaborate or send me an example of some source code that is not behaving as expected?