Using Masa Blazor in MAUI

Using Masa Blazor in MAUI

Using `.NET MAUI`, you can develop applications that run on `Android`, `iOS`, `macOS`, and `Windows`, Linux (community-supported) from a single shared codebase. One codebase runs on multiple platforms.

Last updated 4/26/2022 12:45 PM
MASA 技术团队
12 min read
Category
Blazor MAUI
Topic
Blazor Component Library
Tags
.NET C# Blazor MAUI

1. What is Masa Blazor

Before this, we have already introduced what Masa Blazor is and how to use Masa Blazor. If you are still unfamiliar with Masa Blazor, you can refer to my previous article Getting to Know Masa Blazor. Today, let's explore how to use Masa Blazor in MAUI. First, let's understand what MAUI is.

2. What is MAUI

.NET MAUI stands for .NET Multi-platform App UI, which is a cross-platform framework evolved from Xamarin.Forms. It uses C# and XAML to create native mobile and desktop applications. Here, XAML can be replaced with RazorView. Using .NET MAUI, you can develop applications that run on Android, iOS, macOS, Windows, and Linux (community support) from a single shared codebase — one codebase for multiple platforms.

2.1 Advantages of MAUI

  1. Write cross-platform Visual Studio solutions from a single shared codebase using XAML and C#.
  2. Share UI layouts and designs across platforms.
  3. Share code, tests, and business logic across platforms.
  4. Another advantage is the cross-framework reuse of Razor components, which can be implemented as Razor class libraries (RCL) and shared with Blazor Server and WebAssembly. This maximizes code reuse and enables generating mobile, desktop, and web solutions from a single codebase.

Today, we will focus on hands-on practice and not introduce too many conceptual things. For those who want to learn more about MAUI, please refer to the official documentation What is .NET MAUI?. This article will guide you through creating a common timeline page using MAUI + Masa Blazor for mobile, with a small feature for switching theme colors. The effect is shown below:

Now let's implement it step by step. First, we need to prepare the necessary environment.

Note: The demo environment in this article is (Maui 6.0.200-preview.14.5 + Masa.Blazor 0.3.0)

3. MAUI Environment Setup

  1. Ensure you have installed the latest version of Visual Studio with the Mobile development with .NET workload.

  1. Enable hardware acceleration to maximize Android emulator performance. You can enable Hyper-V or HAXM acceleration. Here we only introduce the first method:
  • In the Windows search box, type "Windows Features" and select "Turn Windows features on or off" from the results. In the "Windows Features" dialog, enable "Hyper-V" and "Windows Hypervisor Platform":

After making these changes, restart your computer.

Ensure that the virtual device created in Android Device Manager uses an x86_64 or x86-based system image. Using an Arm-based system image will not accelerate the virtual device, and it will run slowly. After enabling Hyper-V, you can run the accelerated Android emulator. For detailed settings on HAXM acceleration, refer to: How to use Android Emulator & Enable Hardware Acceleration.

4. Create a MAUI App and Introduce Masa Blazor

  1. Create a new project and select .NET MAUI Blazor App. This allows us to use Blazor View to write the UI.

  1. Install Masa.Blazor from NuGet and register the related service in the MauiProgram.cs file.

builder.Services.AddMasaBlazor();

The CreateMauiApp() method can be simply understood as: in the startup method, an extension method of the builder object RegisterBlazorMauiWebView() is called, and then BlazorWebView itself is added to the DI container's Services collection via the builder.Services property. This performs dependency injection to load platform-specific views for rendering the output HTML. Since each platform has its own web engine, the BlazorWebView (inheriting from View) control can process Razor components at runtime and generate their equivalent HTML. That HTML will be rendered using the platform's native web engine without any web server involvement.

  1. In wwwroot/index.html, include the styles, fonts, and scripts.

<link href="_content/Masa.Blazor/css/masa-blazor.css" rel="stylesheet" />
<link href="_content/Masa.Blazor/css/masa-extend-blazor.css" rel="stylesheet" />
<link
  href="https://cdn.masastack.com/npm/@mdi/font@5.x/css/materialdesignicons.min.css"
  rel="stylesheet"
/>
<link
  href="https://cdn.masastack.com/npm/materialicons/materialicons.css"
  rel="stylesheet"
/>
<link
  href="https://cdn.masastack.com/npm/fontawesome/v5.0.13/css/all.css"
  rel="stylesheet"
/>

<script src="_content/BlazorComponent/js/blazor-component.js"></script>
<script src="https://cdn.masastack.com/npm/echarts/5.1.1/echarts.min.js"></script>
<!-- The echarts script file can be omitted if not needed -->

Note:

  1. In MAUI projects, these files need to be referenced in index.html, not in Pages/_Layout.cshtml as in Blazor.
  2. Starting from Masa Blazor 0.3.0, it adopts the same naming convention as Microsoft (PascalCase). "MASA" was changed to "Masa". So when upgrading to 0.3.0 or later versions, be careful not to miswrite, otherwise the style files and js files will not be found.
  1. In the _Imports.razor file, reference the Masa.Blazor and BlazorComponent namespaces. This way we don't need to reference them in every file.

5. Implement the Timeline Feature

First, design the approximate layout of our page in the layout page MainLayout.razor. We need a Toolbar at the top, a bottom navigation at the bottom, and the child page content in the middle.

This is a common layout. Clicking the menu on the toolbar allows us to switch the theme color. Let's implement it simply with Masa Blazor.

For the top toolbar, we mainly use the MToolbar component and MMenu component. For the bottom, since the BottomNavigation component is not yet available in the official site (it will be released in later versions), we will use the MFooter component instead. This way, our layout template page is ready. The global color is stored in a variable and controlled by the value selected in MMenu.

Mainlayout.razor complete code:

@inherits LayoutComponentBase

<MApp>
  <MToolbar MaxHeight="64" Color="@_color" Dark>
    <MAppBarNavIcon></MAppBarNavIcon>
    <MSpacer></MSpacer>
    Timeline
    <MSpacer></MSpacer>
    <MMenu Left OffsetY Transition="slide-x-transition" Bottom>
      <ActivatorContent>
        <MButton Icon @attributes="@context.Attrs">
          <MIcon>mdi-dots-vertical</MIcon>
        </MButton>
      </ActivatorContent>
      <ChildContent>
        <MList>
          @foreach (var item in _colors) {
          <MListItem OnClick="()=>{_color = item.Value;}">
            <MListItemTitle>@item.Text</MListItemTitle>
          </MListItem>
          }
        </MList>
      </ChildContent>
    </MMenu>
  </MToolbar>

  <div style="width:100%; height:100%">
    <CascadingValue Value="_color"> @Body </CascadingValue>
  </div>

  <MFooter Color="#FAFAFA" Elevation="2">
    <MRow NoGutters Justify="JustifyTypes.SpaceBetween">
      <MCol Style="display:flex; justify-content:center;">
        <MButton Color="@_color" Icon Class="my-2 white--text">
          <MBadge OverLap Color="error" Content="6">
            <ChildContent>
              <MIcon>mdi-chat</MIcon>
            </ChildContent>
          </MBadge>
        </MButton>
      </MCol>
      <MCol Style="display:flex; justify-content:center;">
        <MButton Color="@_color" Icon Class="my-2 white--text">
          <MIcon>mdi-account-details</MIcon>
        </MButton>
      </MCol>
      <MCol Style="display:flex; justify-content:center;">
        <MButton Color="@_color" Icon Class="my-2 white--text">
          <MIcon>mdi-compass</MIcon>
        </MButton>
      </MCol>
    </MRow>
  </MFooter>
</MApp>

@code{
    private string _color = "purple darken-3";
    private List<(string Text, string Value)> _colors = new()
    {
        new("pink", "purple darken-1"),
        new("indigo", "indigo"),
        new("teal", "teal"),
        new("deep-purple", "deep-purple darken-1"),
        new("yellow", "yellow darken-4"),
    };
}

Next, let's implement the Body page, which is our main content. We can find the Timelines component on the Masa Blazor official site and use it directly. The official site happens to have a mobile Timeline demo, but it doesn't have the color-changing feature. No worries, we can take it and modify it.

We copy the code and remove its toolbar because we already have one in the layout page, and it applies to every child page. But here we need to consider how to pass the _color parameter to the Timeline page. We use cascading parameters: pass the parameter to the child page via CascadingValue, and the child page receives it via CascadingParameter. This way, we can access the color variable in the child page.

Timeline.razor complete code:

@page "/"

<MCard Elevation="0" Class="mx-auto">
  <MCard Dark Flat>
    <MButton Absolute Bottom Color="@Color" Right Fab>
      <MIcon>mdi-plus</MIcon>
    </MButton>
    <MImage
      Src="https://cdn.masastack.com/stack/images/website/masa-blazor/cards/forest.jpg"
      Gradient="to top, rgba(0,0,0,.44), rgba(0,0,0,.44)"
      Dark
    >
      <MContainer Class="fill-height">
        <MRow Align="@AlignTypes.Center">
          <strong class="text-h1 font-weight-regular mr-6">8</strong>
          <MRow Justify="@JustifyTypes.End">
            <div class="text-h5 font-weight-light">Monday</div>
            <div class="text-uppercase font-weight-light">February 2015</div>
          </MRow>
        </MRow>
      </MContainer>
    </MImage>
  </MCard>
  <MCardText Class="py-0">
    <MTimeline AlignTop Dense>
      <MTimelineItem Color="pink" Small>
        <MRow Class="pt-1">
          <MCol Cols="3">
            <strong>5pm</strong>
          </MCol>
          <MCol>
            <strong>New Icon</strong>
            <div class="text-caption">Mobile App</div>
          </MCol>
        </MRow>
      </MTimelineItem>

      <MTimelineItem Color="@Color" Small>
        <MRow Class="pt-1">
          <MCol Cols="3">
            <strong>3-4pm</strong>
          </MCol>
          <MCol>
            <strong>Design Stand Up</strong>
            <div class="text-caption mb-2">Hangouts</div>
            <MAvatar>
              <MImage
                Src="https://avataaars.io/?avatarStyle=Circle&topType=LongHairFrida&accessoriesType=Kurt&hairColor=Red&facialHairType=BeardLight&facialHairColor=BrownDark&clotheType=GraphicShirt&clotheColor=Gray01&graphicType=Skull&eyeType=Wink&eyebrowType=RaisedExcitedNatural&mouthType=Disbelief&skinColor=Brown"
              ></MImage>
            </MAvatar>
            <MAvatar>
              <MImage
                Src="https://avataaars.io/?avatarStyle=Circle&topType=ShortHairFrizzle&accessoriesType=Prescription02&hairColor=Black&facialHairType=MoustacheMagnum&facialHairColor=BrownDark&clotheType=BlazerSweater&clotheColor=Black&eyeType=Default&eyebrowType=FlatNatural&mouthType=Default&skinColor=Tanned"
              ></MImage>
            </MAvatar>
            <MAvatar>
              <MImage
                Src="https://avataaars.io/?avatarStyle=Circle&topType=LongHairMiaWallace&accessoriesType=Sunglasses&hairColor=BlondeGolden&facialHairType=Blank&clotheType=BlazerSweater&eyeType=Surprised&eyebrowType=RaisedExcited&mouthType=Smile&skinColor=Pale"
              ></MImage>
            </MAvatar>
          </MCol>
        </MRow>
      </MTimelineItem>

      <MTimelineItem Color="pink" Small>
        <MRow Class="pt-1">
          <MCol Cols="3">
            <strong>12pm</strong>
          </MCol>
          <MCol>
            <strong>Lunch break</strong>
          </MCol>
        </MRow>
      </MTimelineItem>

      <MTimelineItem Color="@Color" Small>
        <MRow Class="pt-1">
          <MCol Cols="3">
            <strong>9-11am</strong>
          </MCol>
          <MCol>
            <strong>Finish Home Screen</strong>
            <div class="text-caption">Web App</div>
          </MCol>
        </MRow>
      </MTimelineItem>
    </MTimeline>
  </MCardText>
</MCard>

@code{
    [CascadingParameter]
    public string Color { get; set; }
}

Then, change the colors that should follow the theme color to be controlled by the Color variable.

In this way, we have completed a timeline page with theme color switching. We could also add more features based on this demo, such as clicking the "+" button to open a dialog and add a timeline task, then render it on the page. That is quite simple, so we won't demonstrate it here. This article mainly introduces how to use Masa Blazor in MAUI and creates a small demo. As a primer, everyone can try using MAUI + Blazor to build some applications and experience it.

Complete sample code: codding-y/Maui.MasaBlazor (github.com)

Open Source Addresses

If you are interested in our MASA Framework, whether it's code contributions, usage, or raising issues, feel free to contact us.

Keep Exploring

Related Reading

More Articles