webBrowserNavigated & NavigationService.GoBack() WP7 - windows-phone-7

What i use:
a list of 10 webbrowsers
a tabIndex ( index of current webbrowser)
different pages that use NavigationService.GoBack() to get to the Mainpage.
the problem:
everytime i use GoBack() to get to the mainpage and navigate, the Navigated-event will be fired 1 time more.
Thats a huge performance issue after some surfing but i don't know why it's happening.
what i do in OnNavigatedTo:
fill the webbrowserlist if count != 10 (global list, only 1 time happening)
set Events for every browsers (maybe the problem, but can't imagine why)
thanks for your help.

If I understand your problem than it is that the webbrowsers Navigated event fires more and more time as you navigate back and forth between the pages.
Without seeing the code I would say that the problem is that you subscribe to the navigated event every time you navigate back to your main page. You could avoid this by:
1) Subscribing to the events in the main pages constructor, becuase it is getting called one time only
2) If you have to subscribe to the events in the pages OnNavigatedTo event than do this checking before:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.NavigationMode != NavigationMode.Back)
{
webbrowser.tap += someFunction;
}
}
if you need to register to the events every time you navigate to the page than to the following:
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
webbrowser.tap -= someFunction;
}

Related

Xamarin forms Navigation issue. Popped page stays active

I have a page "PageA" which listens to a Changed event on a global object.
The page is added in the navigation stack like this:
await Navigation.PushAsync(new PageA());
The page is removed by clicking the back button in the navigation bar.
When I do the same x times, I have x times PageA instances listening to the Changed event. So PageA is created over and over again, but is never really removed.
How do I really get rid of the PageA when clicking the back button?
Example of what you are doing
public partial class MyPage : ContentPage
{
MyPage()
{
this.SomeEvent += SomeEventBeyondTheScopeOfThisPage();
}
protected override void OnDisappearing()
{
//You should add this
this.SomeEvent -= SomeEventBeyondTheScopeOfThisPage();
}
}
Which even if the page is popped from your navigation stack does not remove the reference from MyPage.SomeEvent to SomeEventBeyondTheScopeOfThisPage. So when the Garbage Collector comes along this page is going to stay and this event is going to continue to be listened for.
Just detach the event in OnDisappearing for the simple answer. You dont dispose the page you just detach all references and events outside of its scope. A better idea would be to make your code more modular and not worry about detaching the event. If the event source were coming from within the page itself it would not need to be detached.
public partial class MyPage : ContentPage
{
MyPage()
{
this.SomeEvent += SomeEventWithinPagesScope();
}
private Task SomeEventWithinPagesScope()
{
//My cool event goes here
}
}
If it does have to be global another option would be Messaging Center. I do not believe you have to detach those listeners but I could be wrong.
https://developer.xamarin.com/guides/xamarin-forms/messaging-center/
another reason: NavigationPage.CurrentNavigationTask.Result still refer to the popped page instance. that is why GC will not collect it. unless you navigate to other pages.

How to handle OnBackKeyPress correctly?

To make it simple, I create a new app, which contains MainPage, and Page2.
MainPage has a button, which navigates to Page2. Also override MainPage.OnBackKeyPress:
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
if (MessageBox.Show("Quit?", "Confirm", MessageBoxButton.OKCancel) == MessageBoxResult.Cancel)
e.Cancel = true;
else
base.OnBackKeyPress(e);
}
Page2 is empty, except override OnNavigateFrom, to simulate a long time operation when back from Page2 to MainPage:
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
System.Threading.Thread.Sleep(1000);
base.OnNavigatedFrom(e);
}
Everything is ok, but when I am at Page2, and press Back key 3-4 times very quickly, then I see the message box popup twice.
I expect the message box not shown, or at least show and hide. Is there anything wrong in my code? Thanks.
It depends on what you mean by very quickly...
The code looks OK (apart from the Thread.Sleep which is presumably to simulate a long operation on the UI thread).
I expect this is because while the UI thread is busy (or "sleeping") the back key presses are still registering and being sent to the app, and when the UI thread is available again it will process them one after the other.
This is a good example of why you should avoid blocking the UI thread.

Navigation loop and clearing back-stack

Right now, what I have is, when the user clicks on the page, the page will automatically send the user to a webtask which opens up a pdf file.
What's happening right now is when the user presses the back button, it goes back to the Original page for a split second, before being redirected back to the pdf as I have assigned it to (due to the onnavigateto function)
How would I make it so that, when the user clicks the back button in the pdf document, the app will take the user back to the main page?
Also, on the main page, how do I ensure that the backstack is cleared? (As the Application HAS to exit on the MainPage, so can't go back to the pdf.)
My Code so far, I have tried...
{
public partial class Page2 : PhoneApplicationPage
{
public Page2()
{
InitializeComponent();
}
//as soon as this page is opened, navigate/redirect it to the URL below
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
WebBrowserTask task = new WebBrowserTask() { URL ="http://test.com/test.pdf"};
task.Show();
}
//when the user clicks the hardware back button, instead of taking them to the daily notices, which will send them back to brower
// send the user to the main page
protected override void OnBackKeyPress
(System.ComponentModel.CancelEventArgs e)
{
base.OnBackKeyPress(e);
new Uri("/MainPage.xaml", UriKind.Relative);
}
First of all, why you need the second page that only opens a WebBrowserTask? You can do this from main page.
If you still want to open from second page, you can move WebBrowserTask to constructor and surround it with Dispatcher. This approach is guaranteed that WebBrowserTask will be called only once after navigation to this page (maybe will be some problems with tombstoning). Or, you can save state to PhoneApplicationPage.State to handle where user was and what you should open next.
For clearing back stack you can use next code:
while (NavigationService.BackStack.Any())
{
NavigationService.RemoveBackEntry();
}
You will have to detect this on the application level, rather than the page level. When you 'redirect' the user to the PDF, your application becomes suspended. When they then navigate back, it is resumed.
The Visual Studio template provides a method that it invoked when the application resumes:
// Code to execute when the application is activated (brought to foreground)
// This code will not execute when the application is first launched
private void Application_Activated(object sender, ActivatedEventArgs e)
{
}
Within the above method, you could set a flag, that you then check when your page is navigated to,, that indicates a resume has occurred.

Is it possible to detect the DOM element tapped in a WP7 WebBrowser control?

Is it possible to detect the DOM elements under a spot the user taps on a website using the WP7 WebBrowser control? I would like to let the user identify certain sections of the rendered page.
Yes. This code works pretty well for me:
private void button1_Click(object sender, RoutedEventArgs e)
{
// first define a new function which serves as click handler
webBrowser1.InvokeScript("eval", "this.newfunc_eventHandler = function(e) { window.external.notify(e.srcElement.tagName); }");
// attach function to body
webBrowser1.InvokeScript("eval", "document.body.addEventListener('click', newfunc_eventHandler, false);");
}
private void webBrowser1_ScriptNotify(object sender, NotifyEventArgs e)
{
// this should be called every time you tap an element; the value should be its tag name
Debug.WriteLine(e.Value);
}
It goes along Justin's answer (who beat me while coding). It first defines a click handler which then is attached to the page's body (all via InvokeScript). Every time you tap an element ScriptNotify should be called on the WebBrowser reporting the tapped element's tag name.
Make sure you have set IsScriptEnabled true for your browser control.
I'm guessing you'd have to build something off of the ScriptNotify Event.
At that point, you would register a JavaScript Event handler as usual but that event handler would, in turn, call window.external.notify("someMessageToHandle");. You would then have to route the calls appropriately.
If you don't have the ability to add the JavaScript event handlers directly on the page, you could instead add them using WebBrowserControl.InvokeScript.

Event when PhoneApplicationPage exits

How do I handle the event when a PhoneAppplicationPage (eg. MainPage.xaml) exits?
I tried handling Unloaded event but that doesn't get called when I exit the page.
I think you mean this event :
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
// write exit logic
}
This event is called whenever you navigate away from a page, whether by pressing the back button or the home button. Just paste the above in the code behind class of your page and adjust it to your needs.
What do you mean by exits? You can handle the event when the user presses the back key by subscribing to PhoneApplicationPage.BackKeyPress.
Example:
private void OnBackKeyPress(object sender, System.ComponentModel.CancelEventArgs e)
{
MessageBoxResult messageBoxResult = MessageBox.Show("Are you sure you want to exit?", "Exit?", MessageBoxButton.OKCancel);
if (messageBoxResult != MessageBoxResult.OK)
e.Cancel = true;
}
However when the user exits the application by pressing the home button, search button, a toast notification, incoming call or similar it is called tombstoning. You can handle the Deactivated event on the App to save a state in your application so that you can resume where the user left off the next time the app is started. But you can't "stop" the tombstoning - so that the user cant exit the application.
Read more about tombstoning here:
Architecting WP7 - Part 5 of 10: Tombstoning by Shawn Wildermuth
when a PhoneAppplicationPage ( MainPage.xaml) exits,
this is like form closing event,
MainPage_PointerExited event works in wp8.1.
Even though this thread is 4 years old, I want to answer in case that
may be helpful to others who look for the answer.
Private Sub MainPage_PointerExited(sender As Object, e As PointerRoutedEventArgs) Handles Me.PointerExited
Application.Current.Exit()
'your code goes here
end sub

Resources