I have a WebView in a page and I'm playing a youtube video. When I navigate away from the page to the previous page on the stack, the youtube video in the web view keeps playing the youtube video. Anyone know how to prevent this and kill the WebView when the user navigates away from the page?
EDIT:
Here is how I'm navigating back
private void HtmlViewerPage_BackRequested(object sender, BackRequestedEventArgs e)
{
if (Viewer.CanGoBack)
{
Viewer.GoBack();
e.Handled = true;
return;
}
{
GoBack will navigate the frame stack. It then allows the youtube video to continue to play in the background.
EDIT: I created a sample project that demonstrates my issue.
https://github.com/themimcompany/WebViewIssue
You've registered BackRequested event in MainPage and WebViewPage, but you have not unregistered it when you navigate to other pages. This will cause your issue. When you click back button on WebViewPage, the BackRequested handler will be triggered multi times.
You could remove it in OnNavigatingFrom handler on MainPage.xaml.cs and WebViewPage.xaml.cs.
Please see the following code:
public sealed partial class WebViewPage : Page
{
public WebViewPage()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
var currentView = SystemNavigationManager.GetForCurrentView();
currentView.AppViewBackButtonVisibility = AppViewBackButtonVisibility.Visible;
SystemNavigationManager.GetForCurrentView().BackRequested += WebViewPage_BackRequested;
var site = (e.Parameter as Dictionary<string, string>)["site"];
WebViewer.Navigate(new Uri(site));
}
private void WebViewPage_BackRequested(object sender, BackRequestedEventArgs e)
{
//always try to go back within the WebView first, then try the frame!
if (this.Frame.CanGoBack)
{
if (WebViewer.CanGoBack)
{
WebViewer.GoBack();
e.Handled = true;
}
else
{
WebViewer.NavigateToString("<html>Unloaded.</html>");
WebViewer.NavigateToString("");
var source = WebViewer.Source; // is cleared to null
Frame.GoBack();
e.Handled = true;
}
}
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
SystemNavigationManager.GetForCurrentView().BackRequested -= WebViewPage_BackRequested;
}
}
//MainPage.xaml.cs
private void AppBackRequested(object sender, BackRequestedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame == null)
return;
// If we can go back and the event has not already been handled, do so.
if (rootFrame.CanGoBack && e.Handled == false)
{
e.Handled = true;
rootFrame.GoBack();
}
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
var currentView = SystemNavigationManager.GetForCurrentView();
currentView.AppViewBackButtonVisibility = AppViewBackButtonVisibility.Visible;
SystemNavigationManager.GetForCurrentView().BackRequested += AppBackRequested;
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
SystemNavigationManager.GetForCurrentView().BackRequested -= AppBackRequested;
}
How about overriding the OnNavigatingFrom method and stop the webview?
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
base.OnNavigatingFrom(e);
}
Inside the method try setting the WebView to null, or setting the Source to null or something else
This will stop it:
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
// this will stop any video from playing back.
WebView.NavigateToString("<html>Unloaded.</html>");
base.OnNavigatingFrom(e);
}
Related
I want to hide a button when the user is scrolling through the page so a specific area of the page is not blocked by the button, after the user finish scrolling I will show the button again after a delay of 1000-1500ms. My idea so far is that I will subscribe to the scroll changing event, hide the button, wait for specific delay, show the button again. I managed to implement it for Android platform using effect like this:
public class AndroidScrollingEffect : Xamarin.Forms.Platform.Android.PlatformEffect
{
private bool _isAttached;
public static void Initialize() { }
protected override void OnAttached()
{
if (!_isAttached)
{
Control.ScrollChange += Control_ScrollChange;
_isAttached = true;
}
}
private void Control_ScrollChange(object sender, global::Android.Views.View.ScrollChangeEventArgs e)
{
var command = ScrollingEffect.GetCommand(Element);
command?.Execute(null);
}
protected override void OnDetached()
{
if (_isAttached)
{
Control.ScrollChange -= Control_ScrollChange;
_isAttached = false;
}
}
}
The implementation is working just fine, for android platform. Now, I want to do the same thing for iOS. So, is there an equivalent event for ScrollChange on iOS?
P.S. I want to use effect so I don't write code in the code behind of the page and still able to bind to a specific command in the view model.
Forms ScrollView is rendered as UIScrollView on iOS. So you can try the code below to construct your custom effect:
public class iOSScrollingEffect : PlatformEffect
{
UIScrollView nativeControl;
private bool _isAttached;
protected override void OnAttached()
{
nativeControl = Control as UIScrollView;
if (nativeControl != null && !_isAttached)
{
nativeControl.Scrolled += NativeControl_Scrolled;
_isAttached = true;
}
}
private void NativeControl_Scrolled(object sender, EventArgs e)
{
...
}
protected override void OnDetached()
{
if (_isAttached)
{
nativeControl.Scrolled -= NativeControl_Scrolled;
_isAttached = false;
}
}
}
I would like to use the back function in the UWP in the App.xaml.cs file to change the visibility property of a grid (grid1) on the MainPage.xaml file.
//Go Back
public void App_BackRequested(object sender, Windows.UI.Core.BackRequestedEventArgs e)
{
if(MainPage.MyGlobals.pageLocation == 0)
{
//Do Nothing
}
else if(MainPage.MyGlobals.pageLocation == 1)
{
MainPage.grid1.Visibility = Visibility.Collapsed;
MainPage.MyGlobals.pageLocation = 0;
}
}
I know it's not typical practice to change xaml elements' properties from a different page, but I would really like to change how the back feature works in this app. I believe I have to make the grid pubic, but even when I (thought I) found a way to do that I still couldn't change the properties of the grid with the way I have it written in my code.
As you've mentioned, changing XAML elements' properties from a different page is not a good practice. We can just use SystemNavigationManager.BackRequested event in MainPage like following to change the visibility of a grid.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
SystemNavigationManager.GetForCurrentView().BackRequested += Page_BackRequested;
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
SystemNavigationManager.GetForCurrentView().BackRequested -= Page_BackRequested;
}
private void Page_BackRequested(object sender, BackRequestedEventArgs e)
{
if (MyGrid.Visibility == Visibility.Visible)
{
MyGrid.Visibility = Visibility.Collapsed;
e.Handled = true;
}
else
{
if (this.Frame.CanGoBack)
{
this.Frame.GoBack();
e.Handled = true;
}
}
}
And if you want to take advantage of the back function in App.xaml.cs and use a different function in MainPage, you can add a event in App that wraps SystemNavigationManager.BackRequested to allow other pages to override the default behavior by subscribing to this event like following:
public event EventHandler<BackRequestedEventArgs> BackRequested;
private void App_BackRequested(object sender, BackRequestedEventArgs e)
{
BackRequested?.Invoke(sender, e);
Frame rootFrame = Window.Current.Content as Frame;
if (!e.Handled && rootFrame != null && rootFrame.CanGoBack)
{
rootFrame.GoBack();
e.Handled = true;
}
}
Then in MainPage, subscribe and unsubscribe this event like:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
(Application.Current as App).BackRequested += Page_BackRequested;
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
(Application.Current as App).BackRequested -= Page_BackRequested;
}
It doesn't work because you're trying to access the Grid as if it was a static property of the MainPage. You need a reference to the MainPage instance to manipulate the Grid, but all in all it is a really bad practice. You should have a look at the UWP/WP 8.1 navigation events.
I have a Windows Phone 8.1 app. It consists of 2 pages. On the first page (MainPage.xaml) there is ListView and few buttons. One buton allow to multiselect items on the list. In code I handle back buton, so when user click back in multiselection mode the app won't terminate, but just exit the multiselection mode.
private void HardwareButtons_BackPressed(object sender, BackPressedEventArgs e)
{
if (MultiSelectionButton.Visibility == Visibility.Collapsed)
{
DeleteSelectionButton.Visibility = Visibility.Collapsed;
MultiSelectionButton.Visibility = Visibility.Visible;
TripListView.SelectionMode = ListViewSelectionMode.None;
TripListView.IsItemClickEnabled = true;
e.Handled = true;
}
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
HardwareButtons.BackPressed += HardwareButtons_BackPressed;
this.navigationHelper.OnNavigatedTo(e);
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
HardwareButtons.BackPressed -= HardwareButtons_BackPressed;
this.navigationHelper.OnNavigatedFrom(e);
}
On the second page (HubPage.xaml) there is Hub control, HubSection, and in the HubSection ListView. Similar to the first page I dont want to go back to previous page from selection mode.
private void HardwareButtons_BackPressed(object sender, BackPressedEventArgs e)
{
if (_PeopleListViewInstance.SelectionMode == ListViewSelectionMode.Multiple)
{
_PeopleListViewInstance.SelectionMode = ListViewSelectionMode.None;
DeleteSelectionButton.Visibility = Visibility.Collapsed;
MultiSelectionButton.Visibility = Visibility.Visible;
_PeopleListViewInstance.IsItemClickEnabled = true;
e.Handled = true;
}
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
_vm.Trip = (Trip) e.Parameter;
DataContext = _vm;
HardwareButtons.BackPressed += HardwareButtons_BackPressed;
this.navigationHelper.OnNavigatedTo(e);
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
HardwareButtons.BackPressed -= HardwareButtons_BackPressed;
this.navigationHelper.OnNavigatedFrom(e);
}
Code on the first page works fine, but the second one doesn't.
What I'm doing wrong?
How to customize BackPressed event so that every page when BackPressed returns a specified 'Home' Page. Stack is not required to be maintained.
public App()
{
Windows.Phone.UI.Input.HardwareButtons.BackPressed += HardwareButtons_BackPressed;
this.InitializeComponent();
this.Suspending += this.OnSuspending;
}
private void HardwareButtons_BackPressed(object sender, BackPressedEventArgs e)
{
Frame frame = Window.Current.Content as Frame;
if (frame == null)
{
return;
}
if (frame.CanGoBack && !e.Handled)
{
e.Handled = true;
frame.GoBack();
}
}
You need to override the backpressed method and it needs to be protected.
I got a problam with my WP8.1 application. I have a listView and when I tap on item, it get me to a new page with détails but then when I go back to my listView, I can retap the same item but it don't get me anywhere.
Here is my listView SelectionChanged Handler in MainPage.xaml.cs.
private void lvNom_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Person personneSelect = (Person)lvNom.SelectedItem;
Frame.Navigate(typeof(DetailPersonne), personneSelect);
}
Here is the code behind the page I need to show in DetailPersonne.xaml.cs
public sealed partial class DetailPersonne : Page
{
public Person person;
public DetailPersonne()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
person = e.Parameter as Person;
if(string.IsNullOrEmpty(person.Nom) == true){
tbNom.Text = "Non renseigné.";
}
else{
tbNom.Text = person.Nom;
}
if (string.IsNullOrEmpty(person.Prenom) == true)
{
tbPrenom.Text = "Non renseigné.";
}
else{
tbPrenom.Text = person.Prenom;
}
the only navigation change I've done is handling the hardware back button in my App.xaml.cs
public App()
{
this.InitializeComponent();
this.Suspending += this.OnSuspending;
HardwareButtons.BackPressed += HardwareButtons_BackPressed;
}
void HardwareButtons_BackPressed(object sender, BackPressedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
if(rootFrame != null && rootFrame.CanGoBack)
{
e.Handled = true;
rootFrame.GoBack();
}
}
So if anyone got a fix for that it'll be nice ! Thanks in advance ! :)
try resetting the selected item as SelectionChanged is not firing because the Selection hasnt changed when you navigate back.
private void lvNom_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if(lvNom.SelectedItem != null)
{
Person personneSelect = (Person)lvNom.SelectedItem;
lvNom.SelectedItem = null;
Frame.Navigate(typeof(DetailPersonne), personneSelect);
}
}