Bug 40498 - A NavigationPage XAML class can't be added to another XAML class
Summary: A NavigationPage XAML class can't be added to another XAML class
Status: RESOLVED ANSWERED
Alias: None
Product: Forms
Classification: Xamarin
Component: iOS ()
Version: 2.1.0
Hardware: PC Windows
: --- normal
Target Milestone: ---
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2016-04-18 23:06 UTC by dpedrinha
Modified: 2017-02-07 02:37 UTC (History)
3 users (show)

Tags: ac
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED ANSWERED

Description dpedrinha 2016-04-18 23:06:53 UTC
The following code works fine:

<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyApp.MainTabbedPage">
  <NavigationPage Title="asdfee">
    <x:Arguments>
      <ContentPage Title="asdf">
        <Label Text="asdfawwer"/>
      </ContentPage>
    </x:Arguments>
  </NavigationPage>
</TabbedPage>

But if I want to have the NavigationPage in a separate XAML file, in a different directory, it doesn't work. For example:

<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyApp.MainTabbedPage"
             xmlns:layouts="clr-namespace:MyApp.Layouts">

  <layouts:MyNavigationPage Title="asdfee"/>

</TabbedPage>

Being MyNavigationPage.xaml inside Layouts directory:

<?xml version="1.0" encoding="utf-8" ?>
<NavigationPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyApp.Layouts.MyNavigationPage">
  <x:Arguments>
    <ContentPage Title="asdf">
      <Label Text="asdfawwer"/>
    </ContentPage>
  </x:Arguments>
</NavigationPage>

When I do it this way, it throws the following error:
System.InvalidOperationException: NavigationPage must have a root Page before being used. Either call PushAsync with a valid Page, or pass a Page to the constructor before usage.
Comment 1 Stephane Delcroix 2017-02-06 09:58:13 UTC
It is wrong to assume that this will work.

x:Arguments directive (https://msdn.microsoft.com/en-us/library/ee795382.aspx) is used to pass arguments to non-default constructor. This is what happens in 

<TabbedPage>
  <NavigationPage Title="asdfee">
    <x:Arguments>
      <ContentPage Title="asdf">
        <Label Text="asdfawwer"/>
      </ContentPage>
    </x:Arguments>
  </NavigationPage>
</TabbedPage>

but the effect of x:Arguments on element declaration (attaching it to the root Xaml element) has no defined effect.

when doing

 <layouts:MyNavigationPage Title="asdfee"/>

you actually do

 new MyNavigationPage (); //parameterless ctor

and when the Xaml for 

<NavigationPage x:Class="MyApp.Layouts.MyNavigationPage">
  <x:Arguments>
    <ContentPage Title="asdf">
      <Label Text="asdfawwer"/>
    </ContentPage>
  </x:Arguments>
</NavigationPage>

is inflated, the MyNavigationPage object is already instantiated, and the x:Arguments are ignored.

What you're assuming here is that the  x:Arguments are used while calling the base parameterized ctor, but your default ctor looks like this

 public MyNavigationPage ()
 {}

which is equivalent to 

 public MyNavigationPage () : base ()
 {}

And your expectation would be this

 public MyNavigationPage () : base (Page root)
 {}


which is invalid (root is undefined).

If you're still following at this point (thanks), you've reached the same conclusion I'm at: there's no valid way to get that to work.
Comment 2 dpedrinha 2017-02-07 02:37:58 UTC
I see. But it's not wrong to expect that IMO. 

At least for me. I've worked with Adobe flex before and it had the best xlm layout design I've ever seen. And it was many years ago. I still don't understand why haven't either Android or xamarin followed their path. It's open source now. Worked way better than both xml designs. 

But thanks for the reply.