How To Popup A Xaml Webview Ui Async And Wait For Results
- 19 Oct 2013
I needed to popup a WebView and wait on an event before continuing. There really was no illustration on how to do this so here you all go!
In my scenario I wanted to Navigate to a Uri to do some forms authentication and get some cookies loaded. I knew when I was redirected to a certain Uri the cookie was loaded. To leverage the WebForms based UI I decided to use the WebView control. I would navigate to the Uri to authenticate, then when the browser navigates to another know Uri I would close the browser and continue code execution.
WebView.Navigate returns immediately so you cannot await this call. What you need to do is wait on an event flag then continue execution.
The code is relatively simple and well commented. The key to awaiting this async is the line of code with the Task.Run call. This spins off a thread that allows the UI to refresh. To see the effect, remove the Task.Run and just await the AutoResetEvent. You will see the UI freezes!
Code
Xaml
<Page x:Class="AsyncWebUI.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:AsyncWebUI" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" > <TextBlock VerticalAlignment="Top" HorizontalAlignment="Left" Margin="120,28,0,0"
Text="Wait for Event" FontSize="60"/> <Grid Margin="120,100,0,0"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*"/> </Grid.RowDefinitions> <StackPanel Orientation="Horizontal" Margin="0,10" > <TextBox x:Name="theUri" Width="300" Text=http://blogs.msdn.com/wsdevsol
Margin="0,5,5,5"></TextBox> <Button Content="Navigate" Click="Button_Click" FontFamily="Global User Interface" Margin="5">
</Button> <TextBlock Text="Navigate to http://bing.com to close browser" HorizontalAlignment="Center"
VerticalAlignment="Center" Margin="5,0,0,0"/> </StackPanel> <StackPanel x:Name="hidePanel" Grid.Row="1"> <TextBlock Text="Here is some stuff to hide while navigating" Height="100"></TextBlock> <TextBlock Text="Here is some stuff to hide while navigating" Height="100"></TextBlock> </StackPanel> <WebView x:Name="MyWebView" Grid.Row="1" Visibility="Collapsed"
NavigationCompleted="MyWebView_NavigationCompleted"></WebView> </Grid> </Grid> </Page>
C#
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; using System.Threading; using System.Threading.Tasks; using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls.Primitives; using Windows.UI.Xaml.Data; using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; namespace AsyncWebUI { public sealed partial class MainPage : Page { AutoResetEvent waitForNavComplete; public MainPage() { this.InitializeComponent(); // Create AutoResetEvent initially not set waitForNavComplete = new AutoResetEvent(false); } /// <summary> /// async so we can wait for somethign before proceeding (whatever that may be) /// </summary> async private void Button_Click(object sender, RoutedEventArgs e) { // Hide XAML and bring up the WebView hidePanel.Visibility = Visibility.Collapsed; MyWebView.Visibility = Visibility.Visible; // Go to the site specified MyWebView.Navigate(new Uri(theUri.Text)); // Wait for this AutoResetEvent to be Set // If you just did the Wait the WebView would not come up and the UI would freeze await Task.Run(() => { waitForNavComplete.WaitOne(); }); // Reset the event (unset it) waitForNavComplete.Reset(); // Swap back the UI MyWebView.Visibility = Visibility.Collapsed; hidePanel.Visibility = Visibility.Visible; } void MyWebView_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args) { // I am waiting for a specific Uri. When I see it... if (args.Uri == new Uri("http://www.bing.com")) { // Reset the event so we close the browser and bring up the old XAML waitForNavComplete.Set(); } } } }
Summary
So it is fairly easy to do this. The trick is really in the await Task.Run(() => call. Please drop me a line if you find this useful!
<< Go Back