Calling WinUI from Blazor App Hosted in WebView2

In the previous blog post you learned how you can use JavaScript Interop to call from your WinUI application into your Blazor application that you host in the WinUI app in a WebView2. So, this was just the direction WinUI to Blazor.

But can you also call from the hosted Blazor app into your WinUI app?

Of course you can. To show you how it works, I’ve extended the application from the previous blog post. I’ve added an “Update WinUI from Blazor”Button in the Blazor app, you see it in the screenshot below. When you click this Button, the WinUI TextBox is set to the firstname entered in the Blazor input field.

To achieve this, you can send messages from the hosted web app to the WinUI WebView2. Let’s see how this works.

WinUI: The WebMessageReceived Event

In the WinUI app, let’s register an event handler for the WebView2‘s WebMessageReceived event like below (The three dots … mean that there’s code that I didn’t include in the snippet below. But you find the complete code on GitHub):

public sealed partial class MainPage : Page
{
  public MainPage()
  {
    ...
    webView2.WebMessageReceived += WebView2_WebMessageReceived;
  }
  
...

  private void WebView2_WebMessageReceived(WebView2 sender,
    WebView2WebMessageReceivedEventArgs args)
  {
    txtFirstName.Text = args.WebMessageAsString;
  }
}

As you can see in the code snippet above, the WebView2WebMessageReceivedEventArgs have a WebMessageAsString property. This property contains the received message.

With this code, our WinUI app is ready to receive a string from the Blazor app, so let’s continue in the Blazor app.

Blazor: Set up the JavaScript Code

To send a message from Blazor, you need to execute JavaScript code. The function that you need to execute to send a message is called window.chrome.webview.postMessage. When you call that function from JavaScript, the WebMessageReceived event will be raised on the WinUI app’s WebView2. That means, we just need to call that function from Blazor with the firstname value.

In the Blazor app’s wwwroot folder, I’ve created already in the previous blog post a JavaScript file with an interopFunctions object. Now, let’s add a setFirstNameInWinUI method to that interopFunctions object like below:

interopFunctions.setFirstNameInWinUI = (firstName) => {
   window.chrome.webview.postMessage(firstName);
 };

As you can see, that interopFunctions.setFirstNameInWinUI method is just a wrapper around the window.chrome.webview.postMessage function. The firstName parameter is passed as an argument to the postMessage function. Now we need to call it from Blazor.

Blazor: Call the JavaScript Code

In the Index.razor component I’ve added a button and an event handler for the button’s click event. You can see that code in the snippet below. The event handler is called SetFirstNameInWinUI. In that SetFirstNameInWinUI method, the IJSRuntime is used to call the interopFunctions.setFirstNameInWinUI JavaScript method that you saw in the previous snippet. The firstName field of the Blazor component is passed as an argument to that JavaScript method.

<button class="btn btn-secondary" @onclick="SetFirstNameInWinUI">
  Update WinUI from Blazor
</button>

@code{

  private string firstName = "Julia";

  private async Task SetFirstNameInWinUI()
  {
    await JSRuntime.InvokeVoidAsync("interopFunctions.setFirstNameInWinUI",
      firstName);
  }

That’s it. Now when you click the “Update WinUI from Blazor” Button in the Blazor App, the firstname TextBox in the WinUI app is updated. Great!

Sending Different Messages

In this blog post we were just sending a single message with the firstname from Blazor to the WinUI app. That was easy. But what if you have different messages that you want to send to your WinUI app?

There is just one WebMessageReceived event on the WebView2. To send different messages, you need to have a kind of switch logic in the event handler of that WebMessageReceived event, and that means from JavaScript you need to pass information that allows you to switch in the WinUI app.

Let’s look at an example. The following snippet shows an adjusted setFirstNameInWinUI JavaScript method. Instead of a simple firstname string, it passes a JSON string to the postMessage function. That JSON string contains a JSON object with the properties messageType and value:

interopFunctions.setFirstNameInWinUI = (firstName) => {
  window.chrome.webview.postMessage(JSON.stringify({
    messageType: 'firstName',
    value: firstName
  }));
};

Now in the WinUI app, you can define a WebMessage class that has these two properties:

class WebMessage
{
  public string MessageType { get; set; }
  public string Value { get; set; }
}

In the WebMessageReceived handler of the WebView2 you can now deserialize the received JSON string to a WebMessage object. In the code below I use NewtonSoft’s JsonConvert class. After deserializing the JSON string, you can check on the WebMessage object the MessageType and use the Value. In the case below, the code checks if it’s the firstName message type, and if that’s the case, the value is assigned to the Text property of the firstName TextBox:

private void WebView2_WebMessageReceived(WebView2 sender,
  WebView2WebMessageReceivedEventArgs args)
{
  var jsonString = args.WebMessageAsString;
  var message= JsonConvert.DeserializeObject<WebMessage>(jsonString);
  if(message.MessageType == "firstName")
  {
    txtFirstName.Text = message.Value;
  }
}

That’s it! Now you could send other string messages to your Blazor app and switch by the message type.

Go and grab the code from GitHub.

Summary

Now you’ve seen the Blazor to WinUI communication. In the previous blog post you learned about the WinUI to Blazor communication. That means that you can communicate in both directions, and this makes the integration of Blazor apps and components in WinUI via WebView2 really powerful.

Happy coding!
Thomas

Share this post

Comments (3)

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.