Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hide or modify the toolbar of Webview2 when viewing pdf

Tags:

pdf

webview2

I am using the new Webview2 control to render Pdf files in my WPF application.

This is working well but I would like to customize the toolbar to hide for example the save buttons on some criteria. I did not find methods or properties to do that directly from the Webview2/CoreWebView2 object.

But if I inspect the web page code generated when the pdf is rendered I can see the part where the save buttons are

enter image description here

Is it possible to intercept the whole page before it is rendered and alter the html ? I know it is dirty to do this as it will require to look for the class Id that is subject to change but it will work for now as a temporary solution.

like image 513
Alex R Avatar asked Feb 15 '21 14:02

Alex R


People also ask

How do I hide the top bar of a PDF in Chrome?

The PDF Toolbar that comes up in Google Chrome when displaying a PDF, which displays Filename, Page Number, Rotate Button, Download Button, and Print Button can be suppressed by adding #toolbar=0 to the end of the URL.

How do I disable the toolbar button in PDF?

Question. There is an option to hide the menu bar using the F9 key on the keyboard and Tools bar using the F8 key OR go to View>> Showhide>> Menu bar/Toolbar items.


1 Answers

Yes it is 100% possible to add scripts into your environment, that can intercept and control the content you are rendering.

I'm using WebView2 in windows forms, so I'll show you how I do it in a desktop windows forms application, the process will be similar for other environments, and is almost identical for WPF projects.

Step 1

Setup and initialise the default settings for your webview2 control

public FrmMainForm()
{
  InitializeComponent();

  // Resize/position client to a standard 720p HD TV and make room for tools
  var toolBarSize =
    PnlToolPanelTopRow.Height +
    PnlToolPanelLowerRow.Height;

  SetClientSizeCore(1280, toolBarSize + 720);
  //webview.Top = toolBarSize;
  webview.Height = 720;

  // Webview initialisation handler, called when control instatiated and ready
  webview.CoreWebView2InitializationCompleted += Webview_CoreWebView2InitializationCompleted;

  // Set defaults for tools
  TxtAppUrl.Text = "http://app/";
  TxtUserAgent.Text = DEFAULTUA;
}

Note the "initialization handler" attached to the Initialization completed event.

Step 2

In your initialization event handler, you need to load in the JavaScripts you wish to run every time a browser view is initialised. These scripts are ALWAYS executed before any of the scripts in the loaded page, or before the dom has loaded, they are executed after the page navigation however, so you cannot use them to control the navigation cycle.

Here's an example, from one of my projects

private void Webview_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e)
{
  // Custom URL handler (All URLS starting "http://app/" are intercepted directly by the application
  webview.CoreWebView2.AddWebResourceRequestedFilter("http://app/*", CoreWebView2WebResourceContext.All);
  webview.CoreWebView2.WebResourceRequested += WebResourceRequested;

  // Load in our custom JS API files to create the HbbTv JS environment
  webview.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(JsLoader.LoadApi("BrowserOverrides.js"));

  // Assign any back end C sharp classes to support our JS api's
  webview.CoreWebView2.AddHostObjectToScript("channelData", new ChannelData());

  // Event handler for notification of dom content load finished
  //webview.CoreWebView2.DOMContentLoaded += CoreWebView2_DOMContentLoaded;

  // Show dev tools by default
  webview.CoreWebView2.OpenDevToolsWindow();

  // Other misc settings
  webview.CoreWebView2.Settings.UserAgent = DEFAULTUA;

}

The line you need to pay attention too is the one that reads:

webview.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(JsLoader.LoadApi("BrowserOverrides.js"));

I use a custom loader class, that grabs my java script file from resources compiled into my application, but you however do not need to, the one and only parameter that is passed to the AddScript call is just a plain string of java script code, for example:

webview.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("alert('hello world');");

Will cause your webview2 session to display an alert after every navigation, but before the dom & scripts in the page are loaded and run, for every single page browsed to in the webview.

The JS code has full access to the browser environment, so it's simply a case of attaching a regular JS handler to one of the "dom loaded" or "page loaded" regular java script events, then using standard dom manipulation to find the elements you want and setting their display style to "none".

Step 3 (optional)

You'll see also from my second code snippet, that there are 2 further hook points you can use.

webview.CoreWebView2.AddHostObjectToScript("channelData", new ChannelData());

Adds my custom C# class type "ChannelData" to the browser environment, this is then made available to the browser via the following JS code

chrome.webview.hostObjects.channelData.(method name or property name accessible here)

The "channelData" name, after "hostObjects" is the same as used in the first parameter of the "AddHostObject" call, the second news up a regular C# class which MUST be set up as follows:

using HbbTvBrowser.DataClasses;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;

namespace JsSupportClasses
{
  [ClassInterface(ClassInterfaceType.AutoDual)]
  [ComVisible(true)]
  public class (Class Name Here)
  {
    public string SomeMethod()
    {
      return JsonConvert.SerializeObject(Some C# objects to return);
    }
  }
}

If the class interface and com visible attributes are not provided the class will not be seen by web view and will not be callable.

Any data returned by your methods back to JS code, MUST be a simple data type such as int, bool or string, this means that you cannot return complex objects without first serialising them, then de-serialising them once your back in JS land.

You'll note that there is also a C# level dom ready handler. This is fired as as soon as the HTML is loaded and ready to be accessed, but before images, scripts, css or anything else like that is loaded. You cannot however alter the dom content from C#, at least not at the moment anyway, I do believe it may be on the teams radar for sometime this year, but I cannot confirm that.

While I have not had need to do so my self, I do believe however it is possible to obtain a copy in C# of the loaded HTML, but it is just that "A copy", altering it does not alter the actual loaded dom.

like image 179
shawty Avatar answered Nov 16 '22 03:11

shawty