Tuesday, November 12, 2013

HTML5 IndexedDB – DZone Refcardz


IndexedDB is an exciting browser-based database technology capable of holding large amounts of structured data and conducting high-performance searches using indexes.

DZone.com gave me the opportunity to write another article for their Refcardz series and I'm pleased to announce that my article on HTML5 IndexedDB is now available!

The Refcard introduces you to IndexedDB by guiding you through setting up and using an IndexedDB database, and covers advanced usage and known issues.

The article also contains a link to a github project showing IndexedDB in action. Use the code to better understand IndexedDB or even as a jumping off point for your project.

The DZone.com article can be found here: http://refcardz.dzone.com/refcardz/html5-indexeddb

Thursday, April 11, 2013

HTML5 Web Workers – DZone Refcardz


I've recently had the privilege to work with DZone.com and write an article for their Refcardz series about HTML5 Web Workers.

The article combines the information presented in several of my blog posts and also introduces some new information and concepts like transferable objects, inline workers, as well as a link to a sample project.

The DZone.com article can be found here: http://refcardz.dzone.com/refcardz/html5-web-workers


The following are the blog posts related to HTML5 Web Workers...

Tuesday, November 13, 2012

HTML5 - WebSocket API


Before we start digging into the HTML5 WebSocket API, we need a bit of history to understand why this technology is even needed...

Normally, when you visit a web page with your browser, an HTTP request is sent to the server asking for the page. The server then responds with a result.

Depending on the type of information requested, stock prices for example, the information might be stale by the time you receive the response from the server.

So what do you do?

One common approach has been to have the web page poll the server to check for new information at a set interval as illustrated in the image below:


(click to view the image full size)

In the image above, polling is done every 50 milliseconds.

Polling the server unnecessarily has problems...
  • You're wasting the server's resources as it has to handle your request even if it has no data for you. Depending on how many web pages are checking back for new information, you can actually reduce the scalability of your server.
  • You're wasting network bandwidth as cookies and all kinds of header information has to be passed to the server and back with every request and response


Workarounds like long-polling have been tried where the client makes a request but, unlike with normal polling, the server doesn't return an empty response if it doesn't have any information. Instead, the server holds onto the request until it has some information to return.

When the server has new information, it sends it to the client, along with a complete response.

The client would then immediately make a new request to wait for more information.

Long-polling is basically just polling if the data changes frequently because there will be a bunch of connections made rather than one single connection.


Another workaround approach was to use streaming but some proxy servers and firewalls would actually buffer the messages which slows down the responses.

The result was that apps would either fall back to long-polling, if buffering was detected, or they would need to send the messages using TLS (SSL) but that adds even more overhead to the process because now the server and client also have to encrypt and decrypt the messages.


Workarounds to try and achieve full-duplex communication were also attempted by using two connections: one for the client to talk to the server and one for the server to talk to the client but that can be difficult to set up and coordinate.


Introducing Web Sockets

Web Sockets give you full-duplex functionality with a single connection between the client and server.

Full-duplex allows messages to be passed in both directions at the same time.

HTTP is half-duplex where data can only be passed in one direction at a time. For example, the server cannot respond to a client request until it has finished receiving the request.

A Web Socket connection can also remain open for the life of the session.

Based on tests run by Kaazing Corp, who have been closely involved in the specification process, depending on the amount of HTTP headers, Web Sockets have been tested to provide a 500:1, sometimes even a 1000:1 reduction in unnecessary HTTP header traffic and a 3:1 reduction in latency.

The other nice thing about Web Sockets is that they operate over port 80/443 so there are no firewall or proxy issues to contend with!


To open up a Web Socket, a client starts off with an HTTP handshake asking the server for an upgrade to the Web Socket protocol.

Once the connection is established, messages can be sent back and forth with a 0x00 byte to start the message and a 0xFF byte to end the message.

There are only 2 bytes of overhead compared to the large amount of header information that would usually exist with an HTTP request and response.


With the following example illustration comparing polling with Web Sockets, rather than the client constantly having to ask the server if there are any changes, the client no longer has to ask. The server simply tells the client when it has new information.


(click to view the image full size)


WebSocket object

The following is the current HTML5 WebSocket specification (from the September 20, 2012 W3C Candidate Recommendation):

[Constructor(DOMString url, optional (DOMString or DOMString[]) protocols)]
interface WebSocket : EventTarget {
readonly attribute DOMString url;

// ready state
const unsigned short CONNECTING = 0;
const unsigned short OPEN = 1;
const unsigned short CLOSING = 2;
const unsigned short CLOSED = 3;
readonly attribute unsigned short readyState;
readonly attribute unsigned long bufferedAmount;

// networking
attribute EventHandler onopen;
attribute EventHandler onerror;
attribute EventHandler onclose;
readonly attribute DOMString extensions;
readonly attribute DOMString protocol;
void close([Clamp] optional unsigned short code, optional DOMString reason);

// messaging
attribute EventHandler onmessage;
attribute DOMString binaryType;
void send(DOMString data);
void send(Blob data);
void send(ArrayBuffer data);
void send(ArrayBufferView data);
};


The WebSocket object accepts a url string as the first parameter to the constructor.

The readyState attribute of the WebSocket instance created will hold one of the constants: CONNECTING, OPEN, CLOSING, CLOSED.

The bufferedAmount property holds the number of bytes (UTF-8 text or binary data) that has been queued by the Send() method but has not yet been transmitted to the network.

The byte count does not include the framing overhead or any buffering the operating system or network hardware might do.

There are several event handlers that you can hook into: onopen, onerror, onclose, and onmessage.
  • onopen receives the standard DOM event object
  • onerror...I haven't been able to track down information on what event object the onerror handler receives. In my testing it appears to receive the DOM event object but some sample code on the internet shows a handler accessing a .data property for the error message.
  • onclose receives a CloseEvent object
  • onmessage receives a MessageEvent object

The extensions property is for future use where the server will indicate which extensions, if any, were selected. For now, this is always an empty string.

The protocol property returns the subprotocol selected by the server, if any.

It can be used in conjunction with the array, from the 2nd parameter of the constructor, to perform subprotocol negotiation.

The close method allows you to manually close the Web Socket connection.

It can accept two optional parameters.

If specified, the first parameter must either be 1,000 or in the range of 3,000 to 4,999.

The second parameter is the reason why the close method is being called and has a maximum of 123 bytes.

Note: I haven't been able to get this to work in either Firefox or Chrome. Both seem to ignore the values I'm passing them.

The binaryType property will hold a string with either "blob" or "arraybuffer" for a value.

"blob" is the default value for the binaryType property.

If the binaryType property is set to "blob" then the binary data is returned in Blob form.

If the binaryType property is set to "arraybuffer" then the binary data is returned in ArrayBuffer form.

There are several overloads for the send method available allowing you to send a string, Blob, ArrayBuffer, or ArrayBufferView to the server.


MessageEvent object

The following is the current definition of the MessageEvent object which is found in the HTML5 Web Messaging specification (from the May 1, 2012 W3C Candidate Recommendation):

[Constructor(DOMString type, optional MessageEventInit eventInitDict)]
interface MessageEvent : Event {
readonly attribute any data;
readonly attribute DOMString origin;
readonly attribute DOMString lastEventId;
readonly attribute WindowProxy? source;
readonly attribute MessagePort[]? ports;
};

dictionary MessageEventInit : EventInit {
any data;
DOMString origin;
DOMString lastEventId;
WindowProxy? source;
MessagePort[]? ports;
}

When you receive the MessageEvent object, in your WebSocket's onmessage event handler, the property you will be interested in is the data property.


CloseEvent object

When the Web Socket is closed, the onclose event is triggered and will be passed the CloseEvent object:

[Constructor(DOMString type, optional CloseEventInit eventInitDict)]
interface CloseEvent : Event {
readonly attribute boolean wasClean;
readonly attribute unsigned short code;
readonly attribute DOMString reason;
};

dictionary CloseEventInit : EventInit {
boolean wasClean;
unsigned short code;
DOMString reason;
};

If you call the WebSocket instance's close method without specifying any parameters, the onclose event handler will receive a CloseEvent object containing the following values:
  • wasClean will hold false
  • code will hold 1006
  • reason will be an empty string

For some reason, in my tests using Firefox and Chrome, even if I specify values for the close event parameters, I still end up receiving the default values.


Example JavaScript Code

Before using any technology that might not exist in other browsers you should check to see if the feature exists first.

For Web Sockets, checking to see if the browser supports them is as simple as an if statement check for window.WebSocket

Also, you may want to wrap your Web Socket code in a try/catch statement because the user agent (browser) is expected to throw exceptions if certain conditions are not met.

The following is some very simple JavaScript code showing how to create an HTML5 WebSocket object, how to wire up the events, and how to send a string to the server:

if (window.WebSocket) {
try {
// Create the WebSocket and wire up the event handlers
var wsWebSocket = new WebSocket("ws://echo.websocket.org/");
wsWebSocket.onopen = function (evt) { alert("Connection opened"); }
wsWebSocket.onclose = function (ceCloseEvent) {
alert("Connection closed");
}
wsWebSocket.onerror = function (evt) { alert("we had an error"); }

// The OnMessage event handler is called when we receive data
// from the server

wsWebSocket.onmessage = function (meMessageEvent) {
alert("message from the server: " + meMessageEvent.data);
}

// Send the server a message
wsWebSocket.send("hello from the client");

// You can manually close the WebSocket connection if it's no
// longer needed
// wsWebSocket.close();
} catch (err) { alert("error: " + err.message); }
} else { alert("Sorry. WebSockets are not supported by your browser"); }


In Conclusion

There are several issues to be aware off when working with the HTML5 WebSocket API...
  1. Some browsers won't allow a mixed content environment
    • Can't us a non-secure Web Socket connection (ws://) if the page was loaded with https://
    • Can't use a secure Web Socket connection (wss://) if the page was loaded with http://
  2. Some server errors will be masked with the close code of 1006 and will not specify the actual error in order to prevent a script from being able to distinguish the actual error while probing the network in preparation for an attack. Some of the causes of the 1006 error are:
    • A server whose host name could not be resolved
    • A server to which packets could not successfully be routed
    • A server that refused the connection on the specified port
    • A server that failed to correctly perform a TLS handshake (e.g. the server certificate can't be verified)
    • A server that did not complete the opening handshake (e.g. because it was not a WebSocket server)
    • A WebSocket server that sent a correct opening handshake, but that specified options that caused the client to drop the connection (e.g. the server specified a subprotocol that the client did not offer)
    • A WebSocket server that abruptly closed the connection after successfully completing the opening handshake


Additional Resources

The currently published W3C Candidate Recommendation of the HTML5 WebSocket API specification can be found here: http://www.w3.org/TR/websockets/

The currently published W3C Candidate Recommendation of the HTML5 Web Messaging specification, which contains the definition for the MessageEvent object, can be found here: http://www.w3.org/TR/webmessaging/

The following is a very handy echo server that can be used when testing out the Web Socket technology: ws://echo.websocket.org/

Tuesday, October 30, 2012

Windows 8: Windows Store apps - Privacy Policy


Over the past few articles, we've been talking about creating a Windows Store app. The following are the links to the articles if you're interested:


When I first submitted my app to the Windows Store it failed certification due to the Windows 8 app certification requirement 4.1: http://msdn.microsoft.com/en-us/library/windows/apps/hh694083.aspx

At the time, the 4.1 requirement wasn't entirely clear to me but, after some digging on the internet, I was able determine what was needed.

The good news about the certification requirement documentation is that it appears to be improved over time because section 4.1 is now a bit more clear as to what is needed.


The reason why my app failed certification was because any app that makes a connection to the internet, which our app does, can result in some of your user's personal information making it onto the internet (e.g. the IP address could be used to determine their location).

If you app has the ability to communicate over a network then you need to provide a privacy policy with your app via the Settings charm as well as a link to a web page for use in the Windows App Store gallery.

The privacy policy doesn't have to be legalese but does have to tell the user how their information is used, stored, secured, if it's disclosed with third parties, etc.

Since every app is different, the common recommendation is to go through the Windows Store apps looking at the various privacy policies to come up with one that best fits your app's functionality.


A download of the project (C# and built using Visual Studio Express 2012 for Windows 8) can be found in the following location:
https://github.com/downloads/dovicoapi/DOVICOTimerForWindowsStore/DOVICOTimerForWindowsStore.zip

Friday, September 21, 2012

Windows 8: Windows Store apps - JavaScript passing data to the code containing the WebView control


Over the past few weeks, in my spare time, I've been working on building a Windows Store app that will wrap an HTML web app that I've built.

To use the web app, you enter a token in a textbox on the welcome page and then click the Verify button.

If the token is valid, a URI is given to the user which can then be used for the tracking of one's time using the start/stop timer view in the web app.


The issue that we're going to tackle in this blog post is the following:

When the user clicks the Verify button on the welcome page and a URI is generated, I would like the JavaScript to call the code that holds the WebView control to have the URI saved.

This will save the user the trouble of having to copy the URI, open up the settings flyout, and paste in the new URI.


I know that the JavaScript, of a page loaded in a WebBrowser control, can talk to the C# code when the ObjectForScripting option is turned on but do we have access to a similar feature in a Windows Store app when using a WebView control?


ScriptNotify and AllowedScriptNotifyUris

As it turns out, it is possible for the JavaScript of a page loaded into a WebView control to call into the C# code of the page if you set up a ScriptNotify event.

According to the Microsoft documentation on the ScriptNotify event (http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.controls.webview.scriptnotify), depending on which method you use to display the page in the WebView control, you may or may not have to specify URIs that are allowed to call the event handler.

If you use the WebView's Navigate method then you must specify the list of URIs that are allowed to call the ScriptNotify event handler.

If you use the WebView's NavigateToString method then the list of URIs is not necessary.


I've been simply setting the WebView's 'Source' property with the desired URI so the question is: Do I need to specify the list of URIs or not?

As it turns out, if I don't specify the list of URIs when using the WebView's Source property, the ScriptNotify event does not trigger.

You specify a list of allowed URIs in the following manner:
List<Uri> lstAllowedUris = new List<Uri>();
lstAllowedUris.Add(new Uri("http://apps.dovico.net"));
wvBrowser.AllowedScriptNotifyUris = lstAllowedUris;

Note: The property AllowedScriptNotifyUris almost suggests that you can say one page can make ScriptNotify event handler calls but none of the other pages on the site can.

In reality, based on my testing, even if you specify a URI to a particular page, any page within that domain can call the event handler.

The AllowedScriptNotifyUris property is really a list of allowed domains who's pages are allowed to call the ScriptNotify event handler.


The following is an example of how to wire up a ScriptNotify event handler:
public MainPage()
{
// Only allow the following domain's pages to call our ScriptNotify
// event handler
List<Uri> lstAllowedUris = new List<Uri>();
lstAllowedUris.Add(new Uri("http://apps.dovico.net"));
wvBrowser.AllowedScriptNotifyUris = lstAllowedUris;

// Attach our ScriptNotify event handler
wvBrowser.ScriptNotify += wvBrowser_ScriptNotify;
}

The following is an example of the event handler itself:
void wvBrowser_ScriptNotify(object sender, NotifyEventArgs e)
{
// The string received from the JavaScript code can be found
// in e.Value
}


On the JavaScript side of things, the code is similar to what you would write when calling the C# code of a WebBrowser control with the exception that the function you call is 'notify' where with a WebBrowser control you could define your own callback function name.

The following is an example of the JavaScript code that calls the C# code:
// We have a couple of checks to make sure the 'external'
// object and 'notify' method exist before we try using them
// because our project is a web application and might not be
// running in a WebView control (the checks prevent
// JavaScript errors if the method doesn't exist)
if ((typeof (window.external) !== "undefined") &&
(typeof (window.external.notify) !== "undefined"))
{
window.external.notify(sURI);
}



In Conclusion

Even though the JavaScript is only capable of passing a string to the ScriptNotify event handler, it is highly recommended that you verify the string is in the expected format before trying to use it even if the string came from a source you included in the list of allowed URIs.


Additional Resources

If you are interested in details on how to implement a Settings flyout, especially if you are using a WebView control, I have a previous article that might be of interest: Windows 8: Windows Store apps and the WebView control (we discussed how to display a Settings flyout and focused mostly around making the WebView control play nice with the flyout).

If you are interested in RoamingSettings and the DataChanged event, the following article might also be of interest: Windows 8: Windows Store apps - RoamingSettings and the DataChanged event


A download of the project (C# and built using Visual Studio Express 2012 for Windows 8) can be found in the following location:
https://github.com/downloads/dovicoapi/DOVICOTimerForWindowsStore/DOVICOTimerForWindowsStore.zip

Monday, September 17, 2012

Windows 8: Windows Store apps - RoamingSettings and the DataChanged event


In a previous article (Windows 8: Windows Store apps and the WebView control) we discussed how to display a Settings flyout and focused mostly around making the WebView control play nice with the flyout.

We created a Settings flyout because we want to store the URI that is used by the WebView control.

Now that we have the Settings flyout working, how do we store settings in a Windows Store app?


ApplicationData and RoamingSettings

It turns out that Windows Store apps have access to a class called ApplicationData which allows the storage of session state, user preferences, and other settings.

You have access to the following types of storage with the ApplicationData class:
  • local - persistent data but only on the current device
  • roaming - data that is available to all devices the user has your app installed on
  • temporary - data that can be removed by the system at any point after your app is closed

Local would do the trick but roaming caught my attention.

Being able to set a setting on one device and have all devices, that your app is installed on, automatically know about the new setting sounds pretty neat and would make things a lot easier for the user.


Setting a RoamingSettings key/value pair can be done as follows:
using Windows.Storage;

ApplicationData.Current.RoamingSettings.Values["URI"] = sURI;

Pulling a RoamingSettings value can be done as follows:
string sURI = ApplicationData.Current.RoamingSettings.Values["URI"] as string;
if (!string.IsNullOrWhiteSpace(sURI))
{
// do something with the setting
}


The DataChanged event

Another neat feature of the roaming settings is that you can subscribe to a DataChanged event so that your app can know when a setting was changed on another device.

One thing to be aware of here is that the DataChanged event might not fire at the instant that you set a RoamingSettings value. The synchronization of the roaming app data is controlled by Windows itself.

In our case passing the roaming settings data to other devices instantly is not a concern but what would be nice is if the Settings flyout changes would trigger the DataChanged event in the app where it was changed. As it turns out this is possible...

You can simulate a DataChanged event by calling the SignalDataChanged method after you apply the new settings and it will send a DataChanged event to all registered event handlers:
ApplicationData.Current.SignalDataChanged();


Handling the DataChanged event

Initially, I let Visual Studio wire up my DataChanged event handler (I typed in the += characters and pressed Tab) which gave me the following:
// Don't use this
ApplicationData.Current.DataChanged += DataChangedHandler;

When I ran the application, I discovered an issue where the event is being triggered, because my breakpoint was being hit, but the WebView control was not being updated with the new URI.

After some digging, I discovered that the MSDN documentation for implementing a DataChanged event handler uses the following method:
// Use this
ApplicationData.Current.DataChanged += new TypeEventHandler(DataChangedHandler);

Changing how the DataChanged event handler is registered didn't solve my issue of the WebView control not updating when the URI changes.


Background Threads and the UI Thread

As I was thinking about the issue a thought occurred to me...

Updating the WebView control would be the UI thread's responsibility.

What if the DataChanged event is being received on a background thread?

I've seen the code to call a UI thread in a developer training session at some point in the past (I think it was in regards to Silverlight but I'm not sure).

Either way, I thought I knew what the issue was but I couldn't remember how to get around it so I started searching the internet and I ran across the following MSDN sample code that had just the information I needed: http://code.msdn.microsoft.com/windowsapps/ApplicationData-sample-fb043eb2/sourcecode?fileId=43552&pathId=278302945

The following is the DataChanged event handler you need if you wish to update (directly or indirectly) the UI of your app since the DataChanged event might be triggered on a background thread which has no access to the UI:
async void Current_DataChanged(ApplicationData sender, object args)
{
// DataChangeHandler may be invoked on a background thread, so
// use the Dispatcher to invoke the UI-related code on the UI
// thread.
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
// Cause the web browser to reload in its content
UpdateURI();
});
}



In Conclusion

Overall, RoamingSettings in Windows Store apps are pretty straightforward.

One thing to remember with the DataChanged event, if you need to update the UI (directly or indirectly), is that the event might arrive on a background thread and you will need to dispatch the call to the UI thread.


Additional Resources

The following are some additional resources with regards to ApplicationData and RoamingSettings:
A download of the project (C# and built using Visual Studio Express 2012 for Windows 8) can be found in the following location:
https://github.com/downloads/dovicoapi/DOVICOTimerForWindowsStore/DOVICOTimerForWindowsStore.zip

Wednesday, September 12, 2012

Windows 8: Windows Store apps and the WebView control


I recently started looking into creating a simple Windows 8, Windows Store app, that would contain a browser window and a setting somewhere to allow the URI to be modified.

The app itself is quite simple in concept so I figured it would be a breeze to implement for Windows 8.

To display a web page I needed to use a WebView control and I simply set the Source property to the desired Uri.


The Settings Flyout

After successfully building my solution, and seeing the web page displayed, I decided it was time to move on to building the option to allow a user to modify the URI.

To try and keep things consistent with other Windows Store apps, I decided that it would be best to try and integrate the settings window into the Settings Charm of Windows.

I did some research and integrating into the Settings Charm seemed pretty straightforward in that you simply add an event handler for the CommandsRequested event of the Settings Charm and when the event is called, create your SettingsCommand callback.


Showing a Settings flyout seemed straightforward but I couldn't seem to get it to display.

While searching the internet, looking for articles or forum posts that might shed some light on my issue, I ran across the Callisto open-source toolkit, created by Tim Heuer, that offers boilerplate code for Windows Store apps.

You can find Tim's Callisto blog here: http://timheuer.com/blog/archive/2012/05/31/introducing-callisto-a-xaml-toolkit-for-metro-apps.aspx

The GitHub repository for the Callisto toolkit can be found here: https://github.com/timheuer/callisto

To install the Callisto package into your project via NuGet (https://nuget.org/packages/Callisto), you can use the following command:

PM> Install-Package Callisto


Unfortunately, even with the Callisto toolkit, my settings flyout still wasn't being displayed.

When I was trying to create the settings flyout myself, before I discovered Callisto, I needed to set the height of the flyout so I started to wonder if perhaps the WebView control's VerticalAlignment setting of Stretch was the issue since I wasn't setting an explicit height value.

I set the height of the WebView control to 700 pixels and, when I ran my app, I discovered what the issue really was.

It turns out that the settings flyout was being displayed all along but the WebView control was hiding it because I can now see it being displayed behind the WebView control.


WebViewBrush

After a bit more research, I came to discover that you need a workaround with the WebView control when displaying a flyout (unfortunately, this reminds me of IE 6 and how Select objects would show through a floating div).

The following is the suggested workaround for displaying a flyout over a WebView control:
  • Add a Rectangle object to your view's XMAL with the same dimensions as your WebView control
  • Just before you show the flyout, create a WebViewBrush with the current contents of the WebView control (basically a screen shot)
  • Apply the brush to the Rectangle control
  • Hide the WebView control
  • Display the flyout
  • When the flyout closes, redisplay the WebView control
  • Clear the brush from the Rectangle control

I modified my view to use the workaround and my settings flyout now displays which I'm very happy about.

The main issue that I see now is that there is a noticeable flicker when switching to the WebViewBrush.

My initial thought, since the Redraw method of the brush is asynchronous, was that the WebView control was being hidden a fraction of a second before the brush had time to finish loading resulting in the background of the view being briefly visible causing the flicker.


I tried everything I could think of to get rid of the flicker including making the WebViewBrush a member variable and constructing it during the view's constructor.

I even tried placing the Redraw call before the settings flyout code creation to try and give the brush a few more milliseconds to load but the flicker remained.


async Task.Delay

Something I was curious about was if causing the app to sleep, in between the Redraw call of the brush and the hiding of the WebView, would help.

As it turns out there is no Thread.Sleep method available in a Windows Store app but I did find a workaround using an async Task.Delay(5000) call (I used 5000 milliseconds just so that it was obvious that the sleep call worked)

Much to my pleasant surprise, the flicker disappeared!


When I looked closer at the code, a thought crossed my mind...

I had both the WebViewBrush’s Redraw method as well as the Rectangle's Fill property being set before the delay.

What if the flicker wasn't because of the Redraw method of the brush after all?

What if the issue is with the Fill property of the Rectangle object?

I moved the rectangle's Fill call to after the delay and the flicker returned which indicates to me that the issue is not the brush but rather the Rectangle’s Fill property.


As I started thinking about what the issue might be, a thought occurred to me...

What if this is behaving similar to how the UI thread behaves in a web browser?

In a web browser there is only the one UI thread for a window so when you want to update the UI while processing, your UI request gets added to the end of the list of things that the window plans to do once the currently executing code completes.

Typically, if your code might take a few seconds to complete, you would want to display a processing indicator of some sort while your code executes (so that the user doesn't think that the page froze).

If you simply tell the UI processing control to display and then start processing, the UI control won't display until your code completes since the UI request is queued up for execution next by the browser window and your code is what it's currently working on.

To get around this UI update issue, in a web browser, you tell the UI control to display which adds that item to the end of the window's queue and then you set a timeout to call the function that will do the actual processing which puts the processing function on the queue just after the UI update.

When the original function exits, the UI is updated and then the processing function is called.

Based on the behavior I'm seeing, I believe the Windows Store app is using a similar technique to the UI thread of a web browser window


If I set the Rectangle's Fill property with the WebViewBrush and then add an async delay of 1 millisecond before proceeding to display the settings flyout, there is no flicker!

I still saw the flicker once in a while when closing the Settings flyout via the back button and then redisplaying the flyout really quick. Increasing the delay to about 100 milliseconds seems to improve that scenario.


Example Code

The following is an example of the XAML needed:
<Grid>
<WebView x:Name="wvBrowser" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />

<Rectangle x:Name="rectWebViewBrush" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"></Rectangle>
</Grid>

The following is an example of the source code needed to show the Settings flyout when dealing with a WebView control:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
SettingsPane.GetForCurrentView().CommandsRequested += MainPage_CommandsRequested;
}

protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
SettingsPane.GetForCurrentView().CommandsRequested -= MainPage_CommandsRequested;

base.OnNavigatingFrom(e);
}


// Called by the Settings charm to find out what Settings links
// to display and the code to call when clicked.
void MainPage_CommandsRequested(SettingsPane sender, SettingsPaneCommandsRequestedEventArgs args)
{
// Set up the Link for the Settings charm
SettingsCommand cmdSettingsOptions = new SettingsCommand("cmdSettingsOptionsLabel", "Options", (x) =>
{
// Get a brush from the WebView's content (basically,
// a screen shot)
WebViewBrush wvbBrush = new WebViewBrush();
wvbBrush.SourceName = "wvBrowser";
wvbBrush.Redraw();

// Fill the Rectangle object with the brush
rectWebViewBrush.Fill = wvbBrush;

// Show the settings flyout
ShowSettingsFlyout();
});

// Add our Setting link to our applications list of settings
args.Request.ApplicationCommands.Add(cmdSettingsOptions);
}


// Creates and displays the Settings flyout:
async void ShowSettingsFlyout()
{
// Give the Rectangle a chance to refresh so that we
// don't have flicker
await Task.Delay(100);

// Create the Settings flyout and display it (this is using
// the Callisto open-source toolkit). Additional attributes
// can be set like the background color and header brush
// to better represent your app's look and feel
SettingsFlyout settings = new SettingsFlyout();
settings.FlyoutWidth = Callisto.Controls.SettingsFlyout.SettingsFlyoutWidth.Narrow;
settings.HeaderText = "Options";

// Intercept the setting's closed event so that we can
// switch back to the WebView control
settings.Closed += settings_Closed;

// Our UserControl derived class that holds the controls
// for our settings
settings.Content = new SettingsOptionsContent();

// Switch to the WebViewBrush and then show the
// settings flyout
SwitchToWebViewScreenShot(true);
settings.IsOpen = true;
}


void SwitchToWebViewScreenShot(bool bSwitchToScreenShot)
{
// If we're to show the screen shot then...
if (bSwitchToScreenShot)
{
// Hide the WebView control (MainPage_CommandsRequested
// has already set the rectangle's fill with a screen shot of the
// contents of the WebView control)
wvBrowser.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
}
else // We're to show the WebView again...
{
// Show the WebView control and remove the WebViewBrush
// from the Rectangle
wvBrowser.Visibility = Windows.UI.Xaml.Visibility.Visible;
rectWebViewBrush.Fill = new SolidColorBrush(Colors.Transparent);
}
}


// Called when the Settings flyout closes
void settings_Closed(object sender, object e)
{
// Switch back to the WebView control rather than the screen shot
SwitchToWebViewScreenShot(false);
}



In Summary

WebView controls don't allow a flyout to appear over it and require the use of a WebViewBrush to basically display a screen shot while the flyout is displayed.

The filling of a Rectangle object with a WebViewBrush, and immediately hiding the WebView control, introduces a flicker that can be circumvented by interrupting the UI's processing flow by adding an async delay before hiding the WebView control.

Windows Store apps don't support Thread.Sleep but you can accomplish a similar effect by using 'async Task.Delay'


When I was researching the WebViewBrush flicker issue, several forum posts indicated that there was a bug filed for it so there is potential that the flicker will not be an issue forever.

In the mean time, however, I hope this helps.


Download the Source Code

A download of the project (C# and built using Visual Studio Express 2012 for Windows 8) can be found in the following location:
https://github.com/downloads/dovicoapi/DOVICOTimerForWindowsStore/DOVICOTimerForWindowsStore.zip