How to access and manipulate the DOM and JavaScript of WebView? - c#

I have a WebView that I navigate to a URL, and I want to read the contents, Interact with the JavaScript, etc.
I tried
XAML:
<WebView Name="wv1" LoadCompleted="wv1_LoadCompleted" />
C# code:
private void wv1_LoadCompleted(object sender, NavigationEventArgs e)
{
var uri = e.Uri;
var c = e.Content;
}
The problem is that the e.Uri is returned, but the e.Content is null.
How to access the DOM?
How can I do that?

The problem is that the e.Uri is returned, but the e.Content is null.
The Content property of NavigationEventArgs is used to get the root node of the target page's content. The page is xaml page but not web page. You could verify it with Frame.Navigated event. When page navigated you could get value of Content.
private void RootFrame_Navigated(object sender, NavigationEventArgs e)
{
System.Diagnostics.Debug.WriteLine(e.Content.ToString());
}
If you want to get the web page content. you could refer this reply. With some updates:
To enable an external web page to fire the ScriptNotify event when calling window.external.notify, you must include the page's Uniform Resource Identifier (URI) in the ApplicationContentUriRules section of the app manifest.
The follow eval method used to get body html.
string functionString = #"window.external.notify(document.getElementsByTagName('body')[0].innerHTML)";
await Test.InvokeScriptAsync("eval", new string[] { functionString });
And you could get the return value form ScriptNotify event handler.
private void Test_ScriptNotify(object sender, NotifyEventArgs e)
{
var body = e.Value;
}

Related

How to use CoreWebView2Frame Class in windows application

I have a windows webview2 application where we are automating 3rd party website with too many nested iframes and I want to execute javascript in a particular iframe. I want to know how get CoreWebView2Frame instance for the particular iframe using WebView2. Microsoft documentation didn't help.
I am looking for an example or a documentation to work with CoreWebView2Frame Class and shows how to execute javascript in a particular iframe by using CoreWebView2Frame.ExecuteAsync().
I have gone throught the this thread but it's too difficult for me to understand.
You can get a CoreWebView2Frame by handling FrameCreated event and use it later.
Example:
In the following example, the WebView2 browses this Uri, then we find the iframe inside the page, and store it for later use. Later when the user clicks on a button on the WinForms app, using ExecuteScriptAsync method of the iframe, we click on a link inside the iframe programmatically.
To do so, drop a WebView2 and a Button on the form. Handle Load event of the form and Click event of the button and modify the code like this:
//using Microsoft.Web.WebView2.Core;
CoreWebView2Frame sampleFrame;
private async void Form1_Load(object sender, EventArgs e)
{
webView21.Source = new Uri(
"https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_link_test");
await webView21.EnsureCoreWebView2Async();
webView21.CoreWebView2.FrameCreated += CoreWebView2_FrameCreated;
}
private void CoreWebView2_FrameCreated(object? sender,
CoreWebView2FrameCreatedEventArgs e)
{
if (e.Frame.Name == "iframeResult")
{
sampleFrame = e.Frame;
}
}
private async void button1_Click(object sender, EventArgs e)
{
if (sampleFrame != null && sampleFrame.IsDestroyed() == 0)
{
await sampleFrame.ExecuteScriptAsync(
"document.getElementsByTagName('a')[0].click();");
}
}
Now if you click on the button, the link which is inside the iframe will be clicked.

How to prevent pasted URLs from becoming absolute?

Having a WebBrowser control, I roughly do the following steps:
Navigate to "about:blank".
Turn on design mode in DocumentCompleted event handler.
Paste a HTML string with an # as the URL.
Read the document back from the WebBrowser control.
Step 2 is done by this way:
private void webBrowser1_DocumentCompleted(
object sender,
WebBrowserDocumentCompletedEventArgs e)
{
dynamic axObj = webBrowser1.ActiveXInstance;
axObj.document.designmode = "On";
}
Step 3 is done this way:
private void button1_Click(object sender, EventArgs e)
{
var doc = (HTMLDocument)webBrowser1.Document.DomDocument;
var selection = doc.selection;
var range = (IHTMLTxtRange)selection.createRange();
range.pasteHTML("<p>Read more</p>");
}
Step 4 is done this way:
private void button2_Click(object sender, EventArgs e)
{
MessageBox.Show(this, webBrowser1.DocumentText);
}
What I expect:
I would expect to get a HTML string like this:
<html><body>
<p>Read more</p>
</body></html>
What I actually get:
I get an HTML string where the # URL is prefixed with the current document's URL:
<html><body>
<p>Read more</p>
</body></html>
This happens, no matter whether I navigate to about:blank or e.g. https://www.google.com or any other URL.
My question:
Is there any way to prevent IE/mshtml/WebBrowser control from prefixing the currently loaded URL when pasting anchors?
Update 1:
A possible workaround I can think of is to paste an absolute URL like e.g. http://pseudo-hash.com instead of the # and later when getting the HTML back from the WebBrowser control do a string replace and replace the pseudo placeholder URL back with #.

c# WebBrowser, how I get page content of result page?

I have a c# application with a WebBrowser component.
I set the documentText properties with a string that contains a form and an autosubmit to another page:
In the application the code is:
private void carica_Click(object sender, EventArgs e)
{
browserRoar.DocumentText = formHTML;
browserRoar.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(ShowDocument);
}
private void ShowDocument(object sender,WebBrowserDocumentCompletedEventArgs e)
{
string newContent = (browserRoar.DocumentText);
}
In the webbrowser i see that the new page is the one with results but when i check newContent i find the starting content. How can i get the new content?
Thanks
Fulvio

Detect URL change in WPF WebBrowser

Using the WebBrowser in WPF, how can I check for a change in the URL? is there an even that can be fired when it hits a condition? Below I have a button event that sets the App.browserLinkCheck as the target URL, and opens the WebBrowser instance.
private void btNextWelcomeNewHire_Click(object sender, System.Windows.RoutedEventArgs e)
{
App.borwserLinkCheck = App._PasswordSyncWebLink;
webBrowser.Navigate(new Uri(App.borwserLinkCheck));
//webBrowser.Navigating += webBrowser_Navigating;
}
You can use Navigating event to detect or even cancel navigation in the webBrowser.
You can save the current WebBrowser url and compare it with the new one received in the Navigating event and compare them to see if it has changed.
private Uri currentUri;
void myBrowser_Navigating(object sender, NavigatingCancelEventArgs e)
{
if (currentUri.AbsolutePath != e.Uri.AbsolutePath)
{
// Url has changed ...
// Update current uri
currentUri = e.Uri;
}
}
Thanks to #Omribitan example I have managed to over come the NullException issue by adjusting the code:
private String targetStringToCompare = "www.example.com";
void myBrowser_Navigating(object sender, NavigatingCancelEventArgs e)
{
if (e.Uri.AbsoluteUri.ToString() == targetStringToCompare)
{
// Do something when the change will be detected
}
}

Add a control to the page header in ASP.NET

I'm creating a custom script control in ASP.NET
The purpose of the control is simply a server variant of the tag, used to load javascript files
The main purpose of this control however is to combine multiple scripts into one response so on the client side they see something like
tag for each location, so all scripts registered in the DocumentTop location will be combined into a single tag with the exception of the location "inline", all inline scripts are rendered individually where they exist in the markup
I have also created an httphandler, js.ashx, that does the actual combining of the scripts
Everything is working fine except for the "Head" location, for the two document locations i simply use the ClientScriptManager during prerender but for the Head location i have tried the following code during pre render
var scriptControl = new HtmlGenericControl("script");
scriptControl.Attributes["language"] = "javascript";
scriptControl.Attributes["type"] = "text/javascript";
scriptControl.Attributes["src"] = src;
Page.Header.Controls.Add(scriptControl);
and I get the following error:
The control collection cannot be modified during DataBind, Init, Load, PreRender or Unload phases.
does anyone know how add a control to the page header from within a custom control?
Incidentally, the control is used on a content page that has two nested masters and also has a ScriptManager registered on the root master.
The project is an asp.net 3.5 web application project
Ive discovered an answer to my question.
I don't quite understand the why but the problem lies in when I am trying to add my script control into the head, doing it in the control's PreRender event causes my error but if you add the control during the Page's PreRender event it all works fine and dandy
eg:
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
this.Page.PreRender += new EventHandler(Page_PreRender);
}
void Page_PreRender(object sender, EventArgs e)
{
var scriptControl = new HtmlGenericControl("script");
Page.Header.Controls.Add(scriptControl);
scriptControl.Attributes["language"] = "javascript";
scriptControl.Attributes["type"] = "text/javascript";
scriptControl.Attributes["src"] = "blah.js";
}
I don't know why you get this error but how about using ClientScript like that :
protected void Page_Load(object sender, EventArgs e)
{
string scriptFile = "myscriptFile.js";
if (!this.Page.ClientScript.IsClientScriptIncludeRegistered("myScript"))
{
this.Page.ClientScript.RegisterClientScriptInclude("myScript", scriptFile);
}
}
ClientScriptManager.RegisterClientScriptInclude Method
protected override void OnInit(EventArgs e)
{
EnsureChildControls();
base.OnInit(e);
}
protected void Page_Load(object sender, EventArgs e)
{
HtmlGenericControl js = new HtmlGenericControl("script");
js.Attributes["type"] = "text/javascript";
js.Attributes["src"] = yol.ScriptYol("jquery-1.3.2.min.js");
this.Page.Header.Controls.Add(js);
}

Categories

Resources