MasterDetailPage: Different behaviour on UWP / Android - xamarin

When using MasterDetailPage in Xamarin.Forms it behaves as aspected in Android. Just like a normal Navigation Drawer. Please notice the correct behaviour of the slide-in mechanism and the correct placement of the hamburger-button. The Buttons in the menu work great as well.
The UWP App looks like this. Notice, there is no hamburger-button:
After klicking on a menu-button, the menu is gone without a possibility to get it back:
Here are some code excerpts:
App.xaml.cs
public partial class App : Application
{
public App()
{
MainPage = new NavigationPage(new MenuPage());
}
...
MenuPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="WordDeck.MenuPage"
xmlns:local="clr-namespace:WordDeck;assembly=WordDeck"
Title="WordDeck."
MasterBehavior="Default">
<MasterDetailPage.Master>
<ContentPage Title="Menu">
<StackLayout Orientation="Vertical">
<Button Text="Neues Spiel"
Clicked="MainPage_Clicked"></Button>
<Button Text="Deck Verwaltung"
Clicked="DeckManager_Clicked"></Button>
</StackLayout>
</ContentPage>
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<local:MainPage></local:MainPage>
</MasterDetailPage.Detail>
</MasterDetailPage>
MenuPage.xaml.cs
public partial class MenuPage : MasterDetailPage
{
public MenuPage()
{
InitializeComponent();
}
private void MainPage_Clicked(object sender, EventArgs e)
{
Detail = new MainPage();
Title = "WordDeck.";
IsPresented = false;
}
private void DeckManager_Clicked(object sender, EventArgs e)
{
Detail = new DeckManagerPage();
Title = "Deck Verwaltung";
IsPresented = false;
}
}
MainPage and DeckManagerPage are nearly empty and of type ContentPage.
Why is there no menu Button on UWP?

It's because you're running the UWP app as a desktop app and not on the phone. If you run the app on a mobile phone or emulator you should see the menu as on Android.
If you want to use the hamburger behaviour when running as a desktop app set MasterBehavior = MasterBehavior.Popover on your MasterDetailPage

The main problem is the IsPresented on the desktop hides the drawer.
One way to handle this is not to hide on desktop or tablet.
For example...
// Called from each Clicked Event
private void SetPresentedVisability()
{
switch (Device.Idiom)
{
case TargetIdiom.Phone:
IsPresented = false;
break;
case TargetIdiom.Desktop:
case TargetIdiom.Tablet:
case TargetIdiom.Unsupported:
IsPresented = true;
break;
}
}
Alternately you could ignore any non phone IsPresented setting.
IsPresented = (Device.Idiom == TargetIdiom.Phone) ? false : true;

Related

i want to navigate from a page to an other page

i want to navigate from a page(not main page) which is in a tabbed page to a page when clicking on a button. i tried this :
MainPage = new NavigationPage(new listofinterest());
MainPage = new TabbedPageMain()
{
BarBackgroundColor = Color.FromHex("#F8F8F8"),
};
////////
public partial class listofinterest : ContentPage
{
private async void Add(object sender, EventArgs e)
{
await Navigation.PushAsync(new NavigationPage(new MainPage()));
}
}
it didn't work i get this error
"PushAsync is not supported globally on Android, please use a NavigationPage.'"
i need help please.
The problem is your overriding the MainPage with the TabbedPageMain. Only set it once.
First set the MainPage in App.xaml.cs:
MainPage = new NavigationPage(new MyPage());
Then you can push other pages from MyPage like this:
await Navigation.PushAsync(new MyOtherPage());
it didn't work i get this error "PushAsync is not supported globally on Android, please use a NavigationPage.'" i need help please.
From your code and description, you want to navigate from one of Tabbedpages to other page in project. If yes, please add to a navigation stack is referred to as the root page of the application in App.xaml.cs.
public App()
{
InitializeComponent();
MainPage =new NavigationPage( new tabbedpage.TabbedPage1());
}
then Tabbedpage.xaml:
<TabbedPage
x:Class="FormsSample.tabbedpage.TabbedPage1"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:FormsSample.simplecontrol">
<!-- Pages can be added as references or inline -->
<TabbedPage.Children>
<local:Page1 />
<local:Page3 />
<local:Page4 />
</TabbedPage.Children>
Wanting to navigate Page1 from Tabbedpage to other page.
<ContentPage
x:Class="FormsSample.simplecontrol.Page1"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
Title="page 1">
<ContentPage.Content>
<ScrollView>
<StackLayout x:Name="Contenttest">
<Button
x:Name="btn1"
Clicked="btn1_Clicked"
Text="navigate to another page" />
</StackLayout>
</ScrollView>
</ContentPage.Content>
private void btn1_Clicked(object sender, EventArgs e)
{
Navigation.PushAsync(new simplecontrol.Page5());
}
About Navigation detailed info, please refer to
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/navigation/hierarchical

Remove navigation bar in contentpage Xamarin

I am trying to remove navbar from my pages in Xamarin Forms, but I am not able to get it working. I have tried by adding NavigationPage.SetHasNavigationBar(this, false); inside constructor of page eg.
public RegisterUser ()
{
InitializeComponent ();
NavigationPage.SetHasNavigationBar(this, false);
}
And / or by adding NavigationPage.HasNavigationBar="False" inside xaml page
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="PetApp.Pages.RegisterUser"
NavigationPage.HasNavigationBar="false">
But none of those helps.
Is there some better best practice to just show clean page with scrollview or should it be possible to remove navbar totally?
It works in Mainpage but not the rest of pages that I am navigating to via
await Navigation.PushAsync(new NavigationPage(new RegisterUser()));
I found a solution, instead of using Navigation.PushAsync I used
Navigation.PushModalAsync(new NavigationPage(new RegisterPet()));
and also OnAppearing of RegisterPet page I added SetHasNavigationBar
protected override void OnAppearing()
{
InitializeSettings();
NavigationPage.SetHasNavigationBar(this, false);
base.OnAppearing();
}

ZXing view with FreshMVVM not triggering OnScanResult

Resoution TL;DR : https://gist.github.com/rupe120/78f8a57f0ed7ecacbdc13fa2da8d931a
I created my own scan page, converting the built-in ZXingScannerPage code (https://github.com/Redth/ZXing.Net.Mobile/blob/master/Source/ZXing.Net.Mobile.Forms/ZXingScannerPage.cs) to a Page + PageModel/View concept. The page code is below.
The problem is that OnScanResult is never triggered.
I was using ZXingScannerPage directly previously, and the OnScanResult event was successfully triggering but I wanted the page to follow the same format as the rest of the application. So the QR code I'm using should trigger it.
I must be missing a setup piece in the ZXingScannerView, but I can't see it.
Any thoughts?
SearchQrPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.Pages.SearchQrPage"
xmlns:zxing="clr-namespace:ZXing.Net.Mobile.Forms;assembly=ZXing.Net.Mobile.Forms">
<ContentPage.Content>
<Grid>
<zxing:ZXingScannerView x:Name="scannerView" />
<zxing:ZXingDefaultOverlay x:Name="scannerOverlay"
TopText="Hold your phone up to the QR code"
BottomText="Scanning will happen automatically"
ShowFlashButton="True"/>
</Grid>
</ContentPage.Content>
</ContentPage>
SearchQrPage.xaml.cs
using MyApp.PageModels;
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace MyApp.Pages
{
public partial class SearchQrPage : ContentPage
{
public SearchQrPage()
{
InitializeComponent();
scannerView.Options = new ZXing.Mobile.MobileBarcodeScanningOptions
{
PossibleFormats =
new List<ZXing.BarcodeFormat>
{
ZXing.BarcodeFormat.QR_CODE
}
};
scannerView.OnScanResult += ScannerView_OnScanResult;
scannerOverlay.FlashButtonClicked += ScannerOverlay_FlashButtonClicked;
}
private void ScannerOverlay_FlashButtonClicked(Button sender, EventArgs e)
{
scannerView.ToggleTorch();
}
private void ScannerView_OnScanResult(ZXing.Result result)
{
var model = this.BindingContext as SearchQrPageModel;
if (model == null)
return;
scannerView.IsScanning = false;
if (model.ScanResultCommand.CanExecute(result))
model.ScanResultCommand.Execute(result);
}
}
}
Just set IsScanning = true at the constructor, for example. On the original ZXing's page, they do it on the OnAppearing event.
You've missed it up.

Pushing content page from background thread freezes app

In Xamarin Forms for iOS, I have a custom renderer for a ContentPage that displays a video control. In my Xamarin Forms app, this custom ContentPage is displayed inside a NavigationPage.
I would like to have the video screen open when a specific message comes in via MQTT.
When I open the video page by clicking a link on the main screen, it opens as expected. I know I am receiving the message via MQTT and calling Navigation.PushModalAsync() because of console statements and breakpoints. However, the custom rendered page is not displayed and the UI of my app freezes each time after calling PushModalAsync.
Is there something else I need to do to trigger Navigation.PushModalAsync() based on receiving an MQTT notification in the background of my app?
ViewRoomsPage.axml.cs:
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ViewRoomsPage : ContentPage
{
public ViewRoomsPage()
{
InitializeComponent();
}
public string StreamUri { get; set; }
}
ViewRoomsPage.axml:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyForms.Pages.ViewRoomsPage">
<ContentPage.Content>
</ContentPage.Content>
VideoViewerRenderer.cs (video code removed; this should display a blank red screen. It also works when launched from a button on the main screen)
[assembly: ExportRenderer(typeof(ViewRoomsPage), typeof(ViewRoomsRenderer))]
namespace MyForms.IOS.NativeImplementations
{
public class ViewRoomsRenderer : PageRenderer
{
private IJKFFMoviePlayerController _playerController;
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.OldElement != null || Element == null)
{
return;
}
e.NewElement.BackgroundColor = Color.Red;
}
}
}
Method triggered from receiving an MQTT message
public void PushViewRooms()
{
Device.BeginInvokeOnMainThread(async () =>
{
await Application.Current.MainPage.Navigation.PushModalAsync(new ViewRoomsPage());
});
}
In App.xaml.cs:
public partial class App : Application
{
public App()
{
SetupDependencies(); // using StructureMap
Manager = DependencyContainer.Resolve<IMqttManager>();
Manager.Connect();
InitializeComponent();
var mainPage = new MainPage();
MainPage = new NavigationPage(mainPage);
}
}
The problem was a deadlock caused by a Task.WaitAll() being triggered in another section of code running in the background.
Thanks all who helped sanity check that it wasn't something in the way the renderer was set up.

reaching a page from xamarin.forms inside android project

I'm working on an android app with xamarin. I made tabbed pages. For the second page, i want to show the camerastream from my android camera. For that, some sample code said me I need to use a textureView inside the android part of the app, but that textureview needs to be putted on that second page. Whenever I try to reach a Stacklayout inside that Page, the following error shows up: 'Page1.camera' is inaccessible due to its protection level.
Using x:FieldModifier="public" inside that stacklayout doesn't work either.
Here is the structure of my code to make it more clear
Here I make the tabbed pages:
MainPage = new TabbedPage
{
Children = {
new MainPage(),
new Page1(),
new Page2()
}
};
Inside that Page1 i have this:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="App4.Page1"
Title="Licht">
<StackLayout x:Name="camera" x:FieldModifier="public" Orientation="Vertical">
</StackLayout>
</ContentPage>
And inside the MainActivity.cs i have this where i have to access the camera.
_textureView = new TextureView(Page1.camera);
And this is the structure of my app
And this is the structure of my app
Using x:FieldModifier="public" inside that stacklayout doesn't work either.
I have tried x:FieldModifier="public"in xamarin form, even though I use x:FieldModifier="public", the "camera" property is still private. This feature is not useful.
As far as I know there is no way to access "camera" inside MainActivity.cs in Xamarin form.
As a workaround you can design a page render for android platform and create a TextureView in your page render code.
how to create a page render
_textureView = new TextureView(Page1.camera);
BTW to initialize TextureView you need the object that implements the ISurfaceTextureListener interface at android platform.
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity,ISurfaceTextureListener
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
TextureView textureView = new TextureView(this);
textureView.SurfaceTextureListener = this;
LoadApplication(new App());
}
public void OnSurfaceTextureAvailable(SurfaceTexture surface, int width, int height)
{
//start
}
public bool OnSurfaceTextureDestroyed(SurfaceTexture surface)
{
//stop
}
public void OnSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height)
{
throw new NotImplementedException();
}
public void OnSurfaceTextureUpdated(SurfaceTexture surface)
{
throw new NotImplementedException();
}
}
Please follow the TextureView guide for Android.

Resources