Click here to Skip to main content
15,868,141 members
Articles / Desktop Programming / XAML

WinRT : How to Communicate with WebView JavaScript from C# and Vice Versa

Rate me:
Please Sign up or sign in to vote.
4.47/5 (5 votes)
4 Mar 2014CPOL2 min read 30.4K   1   1
WinRT : How to communicate with WebView Javascript from C# and vice versa

The other day, I was contacted by one of the fellow XAML Disciples (who has been dormant for a long time, but hey ho), who was asking how he might determine if some audio within a web site was playing or not. I thought the problem could be solved using the WebView available in WinRT. Turns out I didn’t get what his actual problem was, and this did not help him. I did however try something out before I answered him, which was how to communicate with the WebView hosted HTML/JavaScript from C# and vice versa.

I thought that may make a semi-useful blog post. So I have provided a dead simple example, the C# code will try and change the FontSize of a DIV within the hosted HTML content by calling a JavaScript function in the hosted HTML content. The JavaScript will then double the incoming FontSize and use it for the DIV, and at the same time tell the C# what the doubled size is via a callback into the C# code. Simple requirement really.

It all starts with the markup which is shown in its entirety below:

XAML
<Page
    x:Class="App1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App1"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Border Background="{StaticResource ApplicationPageBackgroundThemeBrush}" BorderBrush="White"
        BorderThickness="4" Height="400" Width="640" Padding="10">
        <StackPanel>
            <StackPanel.Resources>
                <Style x:Key="RefreshAppBarButtonStyle" TargetType="ButtonBase"
            BasedOn="{StaticResource AppBarButtonStyle}">
                    <Setter Property="AutomationProperties.AutomationId" Value="RefreshAppBarButton"/>
                    <Setter Property="AutomationProperties.Name" Value="Refresh"/>
                    <Setter Property="Content" Value="?"/>
                </Style>
            </StackPanel.Resources>
            <WebView x:Name="webView" Height="300" Width="600"/>
            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="10">
                <Button x:Name="font25" Content="25px" Click="Change25_Click"/>
                <Button x:Name="font40" Content="40px" Click="Change40_Click"/>
                <Button x:Name="font60" Content="60px" Click="Change60_Click"/>
                <Button x:Name="reset" Content="Reset" Click="Reset_Click"/>
            </StackPanel>
        </StackPanel>
    </Border>
</Page>

Nothing fancy there, just a WebView control and a few buttons to change the FontSize of the DIV.

So let's have a look at the C# side of things. Here it is in its entirety:

C#
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Popups;
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 App1
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            webView.ScriptNotify += webView_ScriptNotify;
        }

        async void webView_ScriptNotify(object sender, NotifyEventArgs e)
        {
            var jsScriptValue = e.Value;
            MessageDialog msg = new MessageDialog(jsScriptValue);
            var res =  await msg.ShowAsync();

        }

        private const string htmlFragment =
                    "<html><head><script type='text/javascript'>" +
                    "function doubleIt(incoming){ " +
                    "  var intIncoming = parseInt(incoming, 10);" +
                    "  var doubled = intIncoming * 2;" +
                    "  document.body.style.fontSize= doubled.toString() + 'px';" +
                    "  window.external.notify('The script says the doubled value is ' + doubled.toString());" +
                    "};" +
                    "</script></head><body>
                    <div id='myDiv'>I AM CONTENT</div></body></html>";

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            webView.NavigateToString(htmlFragment);
        }

        private void Reset_Click(object sender, RoutedEventArgs e)
        {
            webView.NavigateToString(htmlFragment);
        }

        private void Change25_Click(object sender, RoutedEventArgs e)
        {
            webView.InvokeScript("doubleIt", new string[] { "25" });
        }

        private void Change40_Click(object sender, RoutedEventArgs e)
        {
            webView.InvokeScript("doubleIt", new string[] { "40" });
        }

        private void Change60_Click(object sender, RoutedEventArgs e)
        {
            webView.InvokeScript("doubleIt", new string[] { "60" });
        }

    }
}

Calling JavaScript from C#

This is done using the WebView.InvokeScript() method, where it expects a name of a function, and a string[] for the arguments.

Calling C# from JavaScript

This is slightly trickier as you need to carry out the following 3 steps:

Step 1: Hook up the WebView.ScriptNotify event

Step 2: Use the result of the NotifyEventArgs.Value from Step 1

Step 3: Get the WebView to actually call the ScriptNotify c# event, which is done via this bit of code:

JavaScript
window.external.notify(..)

NOTE

WinRT makes a big point out of the fact that the WebView control is a regular WinRT control that can be treated as any other element such as applying Transforms, etc., while this is true (I have seen the demos/videos/screenshots). However it seems one area has been missed (at least in Windows 8.0 that
I am currently using), which is that the WebView seems to be the top most element. Try the XAML below and see what you think:

XAML
<Page
    x:Class="App1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App1"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <Grid Background="Black" Grid.Row="0">
            <StackPanel Orientation="Horizontal"  Margin="20">
                <ComboBox Width="150">
            <ComboBoxItem Content="hello1"/>
            <ComboBoxItem Content="hello2"/>
            <ComboBoxItem Content="hello3"/>
            <ComboBoxItem Content="hello4"/>
            <ComboBoxItem Content="hello5"/>
            <ComboBoxItem Content="hello6"/>
            <ComboBoxItem Content="hello7"/>
            <ComboBoxItem Content="hello8"/>
            <ComboBoxItem Content="hello9"/>
            <ComboBoxItem Content="hello10"/>
            <ComboBoxItem Content="hello11"/>
            <ComboBoxItem Content="hello12"/>
            <ComboBoxItem Content="hello13"/>
            <ComboBoxItem Content="hello14"/>
        </ComboxBox>
                <Button Content="Reset" Margin="10,0,0,0" Height="45" />
            </StackPanel>
        </Grid>
        <WebView Grid.Row="1" HorizontalAlignment="Stretch"
                 VerticalAlignment="Stretch" Margin="10,0,10,10" />

    </Grid>

</Page>

For me, the ComboBox popup goes behind the WebView, a tad annoying, and for me makes the WebView pretty unworkable.

As always here is a small demo project: Demo project.zip.


License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)

- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence

Both of these at Sussex University UK.

Award(s)

I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2016
  • Codeproject MVP 2016
  • Microsoft C# MVP 2015
  • Codeproject MVP 2015
  • Microsoft C# MVP 2014
  • Codeproject MVP 2014
  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

Comments and Discussions

 
QuestionHow to load local file in UWP WebView: 5 of 5 Pin
DaveThomas201126-May-16 21:45
DaveThomas201126-May-16 21:45 
Great article! Could you share your experience on how to load local file in UWP (e.g. window 10 phone)

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.