I have switched to using UWP (Windows.UI.Xaml.Controls) but now have lost the ability to detect when the webview tab text changes.
Example of text
I previously used an OnTitleChanged event but I cannot find an alternative for this in UWP.
I can see the 'DocumentTitle' in the webView, and it is always updating when necessary.
WebView wv_Browser = new WebView();
string Example = wv_Browser.DocumentTitle;
I have tried every built in event in the WebView but not one of them seem to fire when this updates.
Can anyone suggest and alternative way to trigger an event or monitor this value?
Unfortunately, there is no OnTitleChanged event in UWP WebView, but you could inject eval function into html page as Mehrzad Chehraz said. Please refer the following detail code.
Make eval function for detecting title changed.
string functionString = " new MutationObserver(function () { window.external.notify(document.title); }).observe(document.querySelector('title'), { childList: true })";
Call InvokeScriptAsync method to inject eval. (call below when webview navigation completed)
await MyWebView.InvokeScriptAsync("eval", new string[] { functionString });
listen value changed in ScriptNotify event handler
private void MyWebView_ScriptNotify(object sender, NotifyEventArgs e)
{
var title = e.Value;
}
For more info please check UWP WebView tutorial.
What I ended up using
private void CreateWebView()
{
WebView webview = new WebView();
webview .DOMContentLoaded += async (s, e) =>
{
WebView_DOMContentLoaded(webview);
};
webview .ScriptNotify += (s, e) => {
. . . Do whatever
};
}
private async void WebView_DOMContentLoaded(WebView sender)
{
string function = #"new MutationObserver(function(mutations){window.external.notify(document.getElementById('pageTitle').innerHTML)}).observe(document.getElementById('pageTitle'),{attributes:true,childList:true,subtree:true});";
await sender.InvokeScriptAsync("eval", new string[] { function });
}
Related
I am trying to add hyperlinks to labels on my Xamarin Forms page. For some reason only the first hyperlink function call works, and subsequent calls to my function hyperlink() seem to be ignored. I am unsure why it only works once.
I think it is because tapGestureRecognizer() can only handle one thing at once, but honestly I am not sure. How can I add hyperlinks to multiple labels on my Xamarin app?
Code for reference:
private void hyperlinkLabel(Uri uri, Label label)
{
var tapGestureRecognizer = new TapGestureRecognizer();
tapGestureRecognizer.Tapped += (s, e) => {
Device.OpenUri((uri));
};
label.GestureRecognizers.Add(tapGestureRecognizer);
}
And then I call it as such:
hyperlinkLabel(new Uri("https://www.mycoolwebsite.com", NewAccountLabel),
hyperlinkLabel(new Uri("https://www.myothercoolwebsite.com"), RegisterLabel);
In one stage of my app (Android & iOS are the ones we care about) we've got three pages which take in details and then open a webView for the user to input their card details to take a payment - this can't be done in the app due to Apple's guidelines.
I need to format the navigation in a way that when the user has finished in the webView it closes and then closes the 3 previous modals to get back to the original page. I've got it all working with the Appearing event so each page just closes itself:
this.Appearing += async (s, e) =>
{
await Navigation.PopModalAsync();
};
The issue I'm now having is that when the user presses the back button on the phone, it closes all of the pages that they've been through already & back to the original. I thought about implementing a custom nav bar and disabling the back button on the hardware but this would cause the same problem with the Appearing event.
Is there any easy way to solve this?
EDIT: Relevant code;
async void OnButtonClicked(object sender, EventArgs eventArgs)
{
if (IsConnected)
{
ActivityIndicator.IsVisible = true;
var button = (Button) sender;
button .IsEnabled = false;
await Navigation.PushModalAsync(new Page());
this.Appearing += (s, e) =>
{
ActivityIndicator.IsVisible = false;
button.IsEnabled = true;
RefreshPage();
};
}
else
{
NoInternetLabel.IsVisible = true;
}
}
Use this:
YourButton.Clicked += OpenPage;
OpenPage looks like this:
async public void OpenPage(object sender, EventArgs args)
{
await Navigation.PushAsync(new PageToShow());
}
You don't have to do anything to handle the PageToShow() closing, that happens by itself when the user presses the back button.
Managed to solve this by using Actions. In each new Page() we passed up an async method to close it once the one after had completed;
var nextPage = new Page(async () =>
{
await Navigation.PopModalAsync();
_completedSuccessfully();
});
await Navigation.PushModalAsync(nextPage);
And in the new page class;
private readonly Action _completedSuccessfully;
public Page(Action completedSuccessfully)
{
_completedSuccessfully = completedSuccessfully;
}
This meant that when the webView closed it called the completedSuccessfully() action and then chained all of them to the original page.
I just got to know about gecko and used it in my application. I am not able to use previous functions like
element.count;
element.Innerhtml;
document.Readystate;
and many other functions.
Are there any alternative functions for gecko browser?
I searched for count method and i found
geckoelemnt.Count<>;
but that is not wat i wnat as it needs an argument. Any useful links would be helpful.
Thanks in advance.
First you must initialize the browser, then listen to some events. The most important is DocumentComplete (documentReady). There is where it enables you to navigate DOMtree
if(!Xpcom.IsInitialized) Xpcom.Initialize("Firefox");
_GeckoWebBrowser _brs = new GeckoWebBrowser() { Dock = DockStyle.Fill };
_brs.Navigate("mypage.html");
_brs.AddMessageEventListener("myFunction", recived);
_brs.DomClick += _brs_DomClick;
_brs.DocumentCompleted += _brs_DocumentCompleted;
capture events:
void _brs_DocumentCompleted(object sender, Gecko.Events.GeckoDocumentCompletedEventArgs e)
{
var ele = _brs.Document.GetElementsByClassName("myCssClass");
//All found elements
foreach (GeckoHtmlElement elem in ele)
{
elem.InnerHtml = "My value";
elem.InsertAdjacentHTML("beforeend",MyDomString);
//and many other functions
}
}
void _brs_DomClick(object sender, DomMouseEventArgs e)
{
//Capture dom click.
}
void recived(string s)
{
//myfunction from javascript
}
Scenario is that when i click start button starts this thread:
var t = new Thread(get_webbrowser_page);
t.SetApartmentState(ApartmentState.STA);
t.Start();
And start this function:
public void get_webbrowser_page()
{
WebBrowser browser = new WebBrowser();
browser.Navigate("http://www.google.com");
string htmla = "as";
browser.DocumentCompleted += (s, e) =>
{
var html = browser.DocumentText;
htmla = html.ToString();
};
MessageBox.Show("ASD=" + htmla);
}
My mission is to simulate a click on href element but i can't do it because DocumentText is always empty.
I've red this WebBrowser - empty DocumentText question but it doesn't works for me.
Where I'm wrong?
First, put the messagebox inside the event handler as the comment from Pragmateek suggest. One note, the DocumentCompleted event is firing per frame/iframe. It's good to know. See this question/answer: https://stackoverflow.com/a/3431520/767926
I have a C# form with a web browser control on it.
I am trying to visit different websites in a loop.
However, I can not control URL address to load into my form web browser element.
This is the function I am using for navigating through URL addresses:
public String WebNavigateBrowser(String urlString, WebBrowser wb)
{
string data = "";
wb.Navigate(urlString);
while (wb.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
data = wb.DocumentText;
return data;
}
How can I make my loop wait until it fully loads?
My loop is something like this:
foreach (string urlAddresses in urls)
{
WebNavigateBrowser(urlAddresses, webBrowser1);
// I need to add a code to make webbrowser in Form to wait till it loads
}
Add This to your code:
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
Fill in this function
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) {
//This line is so you only do the event once
if (e.Url != webBrowser1.Url)
return;
//do you actual code
}
After some time of anger of the crappy IE functionality I've came across making something which is the most accurate way to judge page loaded complete.
Never use the WebBrowserDocumentCompletedEventHandler event
use WebBrowserProgressChangedEventHandler with some modifections seen below.
//"ie" is our web browser object
ie.ProgressChanged += new WebBrowserProgressChangedEventHandler(_ie);
private void _ie(object sender, WebBrowserProgressChangedEventArgs e)
{
int max = (int)Math.Max(e.MaximumProgress, e.CurrentProgress);
int min = (int)Math.Min(e.MaximumProgress, e.CurrentProgress);
if (min.Equals(max))
{
//Run your code here when page is actually 100% complete
}
}
Simple genius method of going about this, I found this question googling "How to sleep web browser or put to pause"
According to MSDN (contains sample source) you can use the DocumentCompleted event for that. Additional very helpful information and source that shows how to differentiate between event invocations can be found here.
what you experiencend happened to me . readyStete.complete doesnt work in some cases. here i used bool in document_completed to check state
button1_click(){
//go site1
wb.Navigate("site1.com");
//wait for documentCompleted before continue to execute any further
waitWebBrowserToComplete(wb);
// set some values in html page
wb.Document.GetElementById("input1").SetAttribute("Value", "hello");
// then click submit. (submit does navigation)
wb.Document.GetElementById("formid").InvokeMember("submit");
// then wait for doc complete
waitWebBrowserToComplete(wb);
var processedHtml = wb.Document.GetElementsByTagName("HTML")[0].OuterHtml;
var rawHtml = wb.DocumentText;
}
// helpers
//instead of checking readState . we get state from DocumentCompleted Event via bool value
bool webbrowserDocumentCompleted = false;
public static void waitWebBrowserToComplete(WebBrowser wb)
{
while (!webbrowserDocumentCompleted )
Application.DoEvents();
webbrowserDocumentCompleted = false;
}
form_load(){
wb.DocumentCompleted += (o, e) => {
webbrowserDocumentCompleted = true;
};
}