I was working on a Windows 8 application tonight, as part of some Azure content that I’m creating, and ran into a weird error. I wanted to share it here in case other people ran into the same issue.
I have a very simple application – it’s essentially a simplified News Reader app that collects a set of RSS or ATOM feeds, displays their items, and allows a user to view the feed item – all within the confines of a Windows Store application. The UI elements are arranged from left to right – feed list (ListBox), item list (ListBox) and item preview (WebView) looking something like this:
Simple, right? This is a common pattern for displaying HTML content, and I’m sure one of the reasons a WebView control was included in the SDK.
OK – now that mock data is displaying like it’s supposed to, we move on to adding the “real” data. Like all good Windows Store applications, the data for the list of feeds should be something users enter through the Windows 8 Settings panel. To make it easy for us to implement custom content for the Settings panel, Tim Heuer created a really useful control in his Windows 8 Callisto library (also available via NuGet) called SettingsFlyout. I added some code based on his sample application to implement the SettingsFlyout, and tested it out.
I was expecting this, but it didn’t turn out that way:
What I saw, was no flyout. Well… not a visible flyout anyway.
What to do?
The obvious answer was fire up Lync and ping Tim on IM 🙂 Talking to Tim, I learned that our friend the WebView control is a bit of a z-order piggie. As it turns out, the SettingsFlyout was actually flying out as expected, but the WebView was obscuring it from view. The problem, in other words had NOTHING TO DO with the SettingsFlyout, or my implementation of it – rather the problem was related to the WebView (which I suspect has it’s problems rooted somewhere in COM, as COM is usually the source of chaos in managed applications…)
So – the fix? A bit klunky, but it seems to work – there is a nifty control included in the WinRT SDK called WebViewBrush. The purpose of this brush, as described by the official MSDN documentation, says it best:
WebView has the characteristic that other UI regions such as controls cannot be rendered on top of the WebView. This is because of how window regions are handled internally, particularly how input events are processed and how the screen draws. If you want to render HTML content and also place other UI elements on top of that HTML content, you should use WebViewBrush as the render area. The WebView still provides the HTML source information, and you reference that WebView through element name binding and the SourceName property.WebViewBrush does not have this overlay limitation.
The clunky part, of course, is that you can’t just use a WebViewBrush to display your content. The MSDN documentation again guides us through how we should implement this: when the Settings panel is opened, “capture” the current content of the WebView control into the WebViewBrush and display that via a Rectangle control, while also hiding the WebView. When the Settings panel is closed, switch back to the real WebView. Here’s my code that shows what I did:
private void RegisterForCommands(SettingsPane sender, SettingsPaneCommandsRequestedEventArgs args)
var feedsCommand = new SettingsCommand("manageFeedsCommand", "Manage Feeds", (feedCommand) =>
// create the settings flyout
SettingsFlyout settings = new SettingsFlyout();
settings.Closed += (s, e) =>
FeedItemWebView.Visibility = Windows.UI.Xaml.Visibility.Visible;
FeedItemWebViewRect.Fill = new SolidColorBrush(Windows.UI.Colors.Transparent);
settings.FlyoutWidth = SettingsFlyout.SettingsFlyoutWidth.Wide;
settings.HeaderBrush = new SolidColorBrush(App.VisualElements.BackgroundColor);
settings.HeaderText = "Manage Feeds";
BitmapImage bmp = new BitmapImage(App.VisualElements.SmallLogoUri);
settings.SmallLogoImageSource = bmp;
settings.Content = new SettingsContent();
// hide the webview due to z-order chaos
WebViewBrush b = new WebViewBrush();
b.SourceName = "FeedItemWebView";
FeedItemWebViewRect.Fill = b;
FeedItemWebView.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
// show the settings panel
settings.IsOpen = true;
So – not the most elegant solution, but enough to be getting on with for now. Viva la cutting edge!
PS – Mad props to Tim Heuer for the AWESOME Callisto library, and helping to set me straight on the WebView control.