Home > Back-end >  LoadFromXaml parse exception inflating MenuBarItem
LoadFromXaml parse exception inflating MenuBarItem

Time:12-15

When I try to use the method to inflate my XAML:

MenuBarItem item = new().LoadFromXaml("<MenuBarItem Text=\"Session\"><MenuFlyoutItem Text=\"New\"/><MenuFlyoutItem Text=\"Save\"/><MenuFlyoutItem Text=\"Load\"/></MenuBarItem>");

the MenuBarItem is created and Text properly assigned but all the MenuFlyoutItems are ommited and not added to the menu.

After reading Load XAML at runtime documentation and particularly the "The LoadFromXaml method can be used to inflate any XAML" and the examples given, I assumed that I can throw any valid XAML into it - from a single button, to a DataTemplate of a ListView, a MenuBarItem for a menu, to a whole ContentPage and it should work. But it's not working in this case - I get Microsoft.Maui.Controls.Xaml.XamlParseException and System.Reflection.TargetInvocationException.

Is this behavior a bug or is documentation missing some details about loading XAMLs?

When I enclose the MenuBarItem in a ContentPage's MenuBarItems like this:

new ContentPage().LoadFromXaml("<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<ContentPage\r\n\txmlns=\"http://schemas.microsoft.com/dotnet/2021/maui\"\r\n\txmlns:x=\"http://schemas.microsoft.com/winfx/2009/xaml\"\r\n\tx:Class=\"LoadRuntimeXAML.CatalogItemsPage\"\r\n\tTitle=\"Catalog Items\">\r\n\t<ContentPage.MenuBarItems>\r\n\t\t<MenuBarItem Text=\"Session\">\r\n\t\t\t<MenuFlyoutItem\r\n\t\t\t\tText=\"New\"/>\r\n\t\t\t<MenuFlyoutItem\r\n\t\t\t\tText=\"Save\"/>\r\n\t\t\t<MenuFlyoutItem\r\n\t\t\t\tText=\"Load\"/>\r\n\t\t</MenuBarItem>\r\n\t</ContentPage.MenuBarItems>\r\n</ContentPage>");

it inflates without error and then when I assign elements from the inflated ContentPage to the MainPage's MenuBarItems they display well. But this is an ugly workaround because I don't need a whole ContentPage, just the MenuBarItem.

CodePudding user response:

Your XAML is not complete, thus cannot be parsed.

What the ContentPage has, that your XAML lacks, is the various xmlns lines, that specify the XML elements used in the XAML.

I have not tested, but try replacing <MenuBarItem with

<MenuBarItem\r\n\txmlns=\"http://schemas.microsoft.com/dotnet/2021/maui\"\r\n\txmlns:x=\"http://schemas.microsoft.com/winfx/2009/xaml\"\r\n

Adapt as needed. Any whitespace can be used anywhere \r\n is shown.

If it doesn't work, also prefix with: <?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n

But I believe that is optional.


As an aside, anything that can be done in XAML, can instead be done in C#. C# markup.

C#, being a complete computational language, can often create dynamic UI more easily than XAML, if you are building a UI that depends on different conditions.

A convenient approach in C#, is to define "helper" methods, that take whatever parameters you want, and creates a specific element. That you add to a given parent element, either via C# markup, or methods of a parent layout class.

Its easy to write helper methods that call other helper methods, to build up a whole layout to your specs, controlled at each step by the parameters that matter to you.

At the top level, you might end up with code like this:

// use custom helper methods and methods of "Grid" class.
Grid grid = MyCreateGrid();
grid.Children.Add(MyCreateRowLabel(text), 1, 0);
grid.Children.Add(
    // OR use C# markup
    new StackLayout
    {
      Children =
      {
        new Label().Text("Code:"),
        ...
      }
    },
    1, 1
);
...

CodePudding user response:

From the official document, it's only using LoadFromXaml for single view or a complete contentPage. I also tried LoadFromXaml for <MenuBarItem Text=\"Session\"><MenuFlyoutItem Text=\"New\"/><MenuFlyoutItem Text=\"Save\"/><MenuFlyoutItem Text=\"Load\"/></MenuBarItem>, and just you said that:

the MenuBarItem is created and Text properly assigned but all the MenuFlyoutItems are ommited and not added to the menu.

But you can achieve it by doing this:

MainPage.xaml:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiApp_loadXaml.MainPage"
             x:Name="contentPage">

   <Button Text="click" Clicked="Button_Clicked" HeightRequest="50"/>

</ContentPage>

MainPage.xaml.cs:

private void Button_Clicked(object sender, EventArgs e)
    {
        var xaml = "<MenuBarItem Text=\"Session\"></MenuBarItem>";
        var xaml1 = "<MenuFlyoutItem Text=\"New\"/>";
        var xaml2 = "<MenuFlyoutItem Text=\"Save\"/>";
        var xaml3 = "<MenuFlyoutItem Text=\"Load\"/>";

        MenuFlyoutItem menuFlyoutItem_1 = new MenuFlyoutItem().LoadFromXaml(xaml1);
        MenuFlyoutItem menuFlyoutItem_2 = new MenuFlyoutItem().LoadFromXaml(xaml2);
        MenuFlyoutItem menuFlyoutItem_3 = new MenuFlyoutItem().LoadFromXaml(xaml3);
        MenuBarItem item = new MenuBarItem();
        item.LoadFromXaml(xaml);

        item.Add(menuFlyoutItem_1);
        item.Add(menuFlyoutItem_2);
        item.Add(menuFlyoutItem_3);

       contentPage.MenuBarItems.Add(item);
    }

It works well.

  • Related