Search code examples
xamluno-platform

Correct approach to make UI only in code, without XAML?


I'm trying to develop Uno apps in linux (MX-linux) using in VS code. I wish to make it without using XAML. Creating the repository with the templates, I proceed to delete the MainPage.xaml file, and replace the InitializeComponent(); with my code of UI.

While this works fairly well in Skia.Gtk platform, the Wasm build fails as it is unable to find MainPage.xaml file.

Here is the beginning portion of the large log while building

Microsoft (R) Build Engine version 16.9.0+57a23d249 for .NET
Copyright (C) Microsoft Corporation. All rights reserved.

  Determining projects to restore...
  All projects are up-to-date for restore.
MSBUILD : error : Generation failed: System.AggregateException: One or more errors occurred. (Generation failed for Uno.UI.SourceGenerators.XamlGenerator.XamlCodeGenerator. System.AggregateException: One or more errors occurred. (Failed to parse file /home/Coding/UnoPrac/UnoPrac.Shared/MainPage.xaml) 

So my question is, am I approaching this the correct way? Sure, I can make the xaml file to just contain the <Page..> element and it works for some platforms, but is it just possible to force Uno to ignore the xaml files if not present?

EDIT: I tested it on windows as well. It seems that the Skia.Gtk platform is unique in that it can run without any of the xaml files, provided the suitable code-behind is present for every InitializeComponent() method in *.xaml.cs files.

I deleted the App.xaml file and added this snippet in place of InitializeComponent() method in App.xaml.cs file

this.Resources = new Microsoft.UI.Xaml.Controls.XamlControlsResources();

Similarly, I deleted the MainPage.xaml file and added this in place of InitializeComponent() method in App.xaml.cs file

    public sealed partial class MainPage : Page
    {
        Button nextPage = new Button() { Content = "Next" };
        TextBlock block = new TextBlock() { Text = "Welcome to Uno" };
        public MainPage()
        {
            //this.InitializeComponent();
            Content = new Grid() { Children = { block, nextPage } };
        }
    }

While this setup works flawlessly in the Skia.Gtk platform, it doesn't work with anything else I tested: UWP, Android and Wasm.

On keeping the xaml files with the empty <Page> element, the Android platform app does work successfully, while the UWP encounters a runtime error, and the Wasm app runs but the Page is blank (i.e no component appears).

If the code used for the Gtk platform is able to ignore the xaml files, is there any equivalent for the other platforms in Uno? Or is this approach not possible at all?


Solution

  • I figured the needed change. I initially thought the issue was in the individual platforms, but now I understand the only reason the Skia.Gtk port was running, unlike the other platforms, was because the build errors were failing silently in it.

    To solve the issue, all dependency on any xaml file is to be removed In the *.Shared.projitems. According to my testing, the App.xaml itself can be removed and replaced according to the question and it will run perfectly fine on Android, Linux(Skia.Gtk) and WebAssembly. However, the UWP has some internal dependency on the App.xaml file so in the end I couldn't remove it. But, on removing the references of all the other xaml files, All ports that I tested (UWP, Android, Skia.Gtk and WebAssembly) are running without issue.

    Just for the sake of completeness, I'll include my edited *.Shared.projitems below

    <?xml version="1.0" encoding="utf-8"?>
    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <PropertyGroup>
        <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
        <HasSharedItems>true</HasSharedItems>
        <SharedGUID>6279c845-92f8-4333-ab99-3d213163593c</SharedGUID>
      </PropertyGroup>
      <PropertyGroup Label="Configuration">
        <Import_RootNamespace>UnoPrac</Import_RootNamespace>
      </PropertyGroup>
      <ItemGroup>
        <ApplicationDefinition Include="$(MSBuildThisFileDirectory)App.xaml">
          <SubType>Designer</SubType>
          <Generator>MSBuild:Compile</Generator>
        </ApplicationDefinition>
      </ItemGroup>
      <ItemGroup>
        <Compile Include="$(MSBuildThisFileDirectory)*.cs"/>
      </ItemGroup>
      <ItemGroup>
        <None Include="$(MSBuildThisFileDirectory)Assets\SharedAssets.md" />
      </ItemGroup>
      <ItemGroup>
        <PRIResource Include="$(MSBuildThisFileDirectory)Strings\en\Resources.resw" />
      </ItemGroup>
    </Project>
    

    Oh and the reason I got a "blank" page in the Wasm app was simply because the background was white, along with all the components on it. So I only needed to set the background of the page as black.