This project shows you how you can run Meadow within a MAUI application. In this particular example, we're going to have a clickable button on a MAUI page that will increment a counter and will be shown on a TFT SPI 240x240 round display using Meadow.Foundation's MicroGraphics.
Meadow.Foundationa platform for quickly and easily building connected things using.NET on Meadow. Created by Wilderness Labs, it's completely open source and maintained by the Wilderness Labs community.
If you're new working with Meadow, I suggest you go to the Getting Started w/ Meadow by Controlling the Onboard RGB LEDproject to properly set up your development environment.
Step 1 - Assemble the circuitWire your project like this:
Create a new MAUI app project in Visual Studio 2022 for Windows and name it MauiMeadow.
Step 3 - Add the required NuGet packagesFor this project, search and install the following NuGet packages:
Step 4 - Add FT232H native library to your projectAdd the native library (libmpsse.dll) of the FT232H IO Expander depending on your CPU's architecture (Win32 or x64) to your project and set the Copy to Output Directory
to Copy if newer
or Copy always
.
App.xaml.cs
Copy the following code below:
public partial class App : MauiMeadowApplication<Meadow.Windows>
{
public App()
{
InitializeComponent();
LoadMeadowOS();
MeadowInitialize();
MainPage = new AppShell();
}
protected Task MeadowInitialize()
{
var expander = new Ft232h();
var display = new Gc9a01
(
spiBus: expander.CreateSpiBus(),
chipSelectPin: expander.Pins.C0,
dcPin: expander.Pins.C1,
resetPin: expander.Pins.C2
);
Resolver.Services.Add<IGraphicsDisplay>(display);
return Task.CompletedTask;
}
}
Its important to note that the App class extends from MauiMeadowApplication<Meadow.Windows>
, and in the constructor we call LoadMeadowOS();
to start running Meadow.OS within the MAUI app.\
From the constructor, we also call MeadowInitialize(), which this method initializes any peripherals connected to your PC, in this case, instantiates the FT232H IO Expander to use its pins to initialize the GC9A01 round display.
Lastly, we use add the display to the Resolver.Services so we can get this object from anywhere in the app (in this case, a ViewModel).
MainPageViewModel.cs
Add a new MainPageViewModel
class to your project and copy the following:
public class MainPageViewModel : INotifyPropertyChanged
{
private MicroGraphics graphics;
private IGraphicsDisplay _display;
public ICommand CountCommand { get; set; }
public int Counter { get; set; } = -1;
public MainPageViewModel()
{
CountCommand = new Command(UpdateCounter);
_ = Task.Run(WaitForDisplay);
}
private async Task WaitForDisplay()
{
while (_display == null)
{
_display = Resolver.Services.Get<IGraphicsDisplay>();
await Task.Delay(100);
}
graphics = new MicroGraphics(_display)
{
CurrentFont = new Font12x16(),
Stroke = 2,
Rotation = RotationType._180Degrees
};
UpdateCounter();
}
public void UpdateCounter()
{
Counter++;
graphics.DrawRectangle(
x: 0,
y: 0,
width: graphics.Width,
height: graphics.Height,
color: Meadow.Foundation.Color.FromHex("10485E"),
filled: true);
graphics.DrawText(
x: graphics.Width / 2,
y: graphics.Height / 4 + 10,
text: $"Clicked",
scaleFactor: ScaleFactor.X2,
alignmentH: Meadow.Foundation.Graphics.HorizontalAlignment.Center,
alignmentV: Meadow.Foundation.Graphics.VerticalAlignment.Center);
graphics.DrawText(
x: graphics.Width / 2,
y: graphics.Height / 2,
text: $"{Counter}",
scaleFactor: ScaleFactor.X3,
alignmentH: Meadow.Foundation.Graphics.HorizontalAlignment.Center,
alignmentV: Meadow.Foundation.Graphics.VerticalAlignment.Center);
graphics.DrawText(
x: graphics.Width / 2,
y: graphics.Height * 3 / 4 - 10,
text: $"Times!",
scaleFactor: ScaleFactor.X2,
alignmentH: Meadow.Foundation.Graphics.HorizontalAlignment.Center,
alignmentV: Meadow.Foundation.Graphics.VerticalAlignment.Center);
graphics.Show();
}
#region INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
#endregion
}
A few things to consider in this class:
CountCommand
- a command that will be data bound to the MainPage view and its purpose is to refresh the round display with the counter incremented by one each time is called using MicroGraphics drawing primitives like drawing text and shapes.WaitForDisplay
- a fire and forget task invoked from the ViewModel's constructor. Since we're starting MeadowOS around the same time the MAUI app starts, we cant know when the display is initialized and can be referenced using the resolver, which we have a while loop checking when the display object is retrieve and we can continue making a MicroGraphics object and load the counter UI.
MainPage.xaml
Copy the following XAML code below:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
Shell.NavBarIsVisible="false"
x:Class="MauiMeadow.MainPage">
<Border
BackgroundColor="#1A80AA"
Stroke="White"
StrokeThickness="5">
<VerticalStackLayout
Spacing="30"
Padding="30,0"
VerticalOptions="Center">
<Image
Source="meadow.png"
HeightRequest="200"
HorizontalOptions="Center">
<Image.Shadow>
<Shadow Brush="Black"
Offset="-20,20"
Radius="30"
Opacity="0.25" />
</Image.Shadow>
</Image>
<Label
Text="Meadow on MAUI"
TextColor="White"
SemanticProperties.HeadingLevel="Level1"
FontSize="32"
HorizontalOptions="Center" />
<Label
Text="Click the button and see the counter go up!"
TextColor="White"
SemanticProperties.HeadingLevel="Level2"
FontSize="22"
HorizontalOptions="Center" />
<Button
Text="Click me"
FontSize="Large"
Background="#23ABE3"
TextColor="White"
SemanticProperties.Hint="Counts the number of times you click"
Command="{Binding CountCommand}"
HorizontalOptions="Center">
<Button.Shadow>
<Shadow Brush="Black"
Offset="-5,5"
Radius="20"
Opacity="0.25" />
</Button.Shadow>
</Button>
</VerticalStackLayout>
</Border>
</ContentPage>
This is basically the MAUI app's UI that shows an Image of the circuit board with the FT232H IO expander and the GC9A01 round display, along with a Click Me button that is data bound to the CountCommand
explained earlier in the ViewModel.
MainPage.xaml.cs
Next we need to set the binding context with a new ViewModel we added earlier:
public partial class MainPage : ContentPage
{
int count = 0;
public MainPage()
{
InitializeComponent();
BindingContext = new MainPageViewModel();
}
}
Step 5 - Run the projectClick the Run button in Visual Studio, and when the MAUI app loads, click on the button and look at the counter updating in the round display:
- This project is only the tip of the iceberg in terms of the extensive exciting things you can do with Meadow.Foundation.
- It comes with a huge peripheral driver library with drivers for the most common sensors and peripherals.
- The peripheral drivers encapsulate the core logic and expose a simple, clean, modern API.
- This project is backed by a growing community that is constantly working on building cool connected things and are always excited to help new-comers and discuss new projects.
Comments
Please log in or sign up to comment.