.NET Multi-platform App UI (.NET MAUI) is a framework for building modern, multi-platform, natively compiled iOS, Android, macOS, and Windows apps using C# and XAML in a single codebase [3]. This blog show how to use draw a graphical object in .NET MAUI app.
.Net MAUI provides Microsoft.Maui.Graphics namespace that allow to draw and paint shape, images, compositing operations, and transforming graphical object on a GaphicsView.
To draw graphical objects, we create a class named GraphicsDrawable which derives from IDrawable interface and implements its Draw method. All graphical objects will be drawn from this method.
namespace Graphics
{
public class GraphicsDrawable : IDrawable
{
public void Draw(ICanvas canvas, RectF rectF)
{
// Drawing code goes here
}
}
}
In the Draw method, the ICanvas argument is used for drawing graphical objects and another for specifying size and location of the drawing canvas.
Next, we define a ContentPage.Resource that contains object of class GraphicsDrawable and a GraphicsView control to consume it.
<?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"
xmlns:GraphicsHandler ="clr-namespace:Graphics"
x:Class="Graphics.MainPage">
<ContentPage.Resources>
<GraphicsHandler:GraphicsDrawable x:Key="gDrawable" />
</ContentPage.Resources>
<VerticalStackLayout>
<GraphicsView Drawable="{StaticResource gDrawable}" HeightRequest="300" WidthRequest="400" />
</VerticalStackLayout>
</ContentPage>
Drawing graphical object in GraphicsView
canvas
Drawing a line
Draws a line from the start point (20, 20) to the end point (80, 80) of the line.
public void Draw(ICanvas canvas, RectF rectF)
{
canvas.StrokeColor = Colors.Blue;
canvas.StrokeSize = 3;
canvas.DrawLine(20, 20, 80, 80);
}
The result:
Drawing an ellipse
Draws an ellipse at (50, 50), width = 100, height = 50
public void Draw(ICanvas canvas, RectF rectF)
{
canvas.StrokeColor = Colors.Blue;
canvas.StrokeSize = 3;
canvas.DrawEllipse(50, 50, 100, 50);
}
The result:
Drawing a rectangle
Rectangles and squares can be drawn at (40, 40) size 50x 80 as follow
public void Draw(ICanvas canvas, RectF rectF)
{
canvas.StrokeColor = Colors.DarkBlue;
canvas.FillColor = Colors.DarkBlue;
canvas.StrokeSize = 3;
canvas.DrawRectangle(40, 40, 50, 80);
}
The result:
Drawing an arc
Draw an arc at (20, 20), size 100x100, startAngle = 0, and endAngle = 270, clockwise = true and closed = false
public void Draw(ICanvas canvas, RectF rectF)
{
canvas.StrokeColor = Colors.Teal;
canvas.StrokeSize = 3;
canvas.DrawArc(20, 20, 100, 100, 0, 270, false, false);
}
The result:
Draw a FillArc at (20, 20), size 100x100, startAngle = 180, and endAngle = 360, closed = true
public void Draw(ICanvas canvas, RectF rectF)
{
canvas.FillColor = Colors.Teal;
canvas.FillArc(20, 20, 100, 100, 180, 360, true);
}
The result:
Drawing a path
A path is a collection of one or more contours that contain straight lines and/or curves. We can use the paths to draw curves and complex shapes on the ICanvas by the DrawPath method, which requires a PathF instance.
A contour begins when you call call to the PathF.MoveTo method, that a point at the beginning of the contour and an initial current point. Then we can call the following methods to continue the contour with a line or curve shape from current point:
- LineTo: Adds a straight line to the path.
- CurveTo: Adds a cubic Bezier spline.
- QuadTo: Adds a quadratic Bezier spline.
- AddArc: Adds an arc.
The following code example shows how to draw a path.
public void Draw(ICanvas canvas, RectF rectF)
{
PathF path = new PathF();
path.MoveTo(50, 50);
path.LineTo(100, 200);
path.LineTo(200, 100);
path.Close();
canvas.StrokeColor = Colors.Green;
canvas.StrokeSize = 3;
canvas.DrawPath(path);
}
The result:
Drawing a string
Draw String in a bounding box at (x, y), box size: with x height, horizontal alignment, vertical alignment options. Furthermore, the Font, FontColor, and FontSize properties is also specified
using Font = Microsoft.Maui.Graphics.Font;
public void Draw(ICanvas canvas, RectF rectF)
{
canvas.FontColor = Colors.Black;
canvas.FontSize = 14;
canvas.Font = Font.DefaultBold;
canvas.DrawString("This text is displayed using the bold system font.", 20, 140, 350, 100, HorizontalAlignment.Left, VerticalAlignment.Top);
canvas.Font = new Font("Arial");
canvas.FontColor = Colors.Black;
canvas.SetShadow(new SizeF(5, 6), 4, Colors.Gray);
canvas.DrawString("This text has a shadow.", 20, 200, 300, 100, HorizontalAlignment.Left, VerticalAlignment.Top);
canvas.Font = Font.Default;
canvas.DrawString("Text is left aligned.", 20, 20, 370, 90, HorizontalAlignment.Left, VerticalAlignment.Top);
canvas.DrawString("Text is centered.", 20, 60, 370, 90, HorizontalAlignment.Center, VerticalAlignment.Top);
canvas.DrawString("Text is right aligned.", 20, 100, 380, 90, HorizontalAlignment.Right, VerticalAlignment.Top);
}
The result:
Images
Images are represented by the IImage interface.
Note that: There are two different IImage interfaces in NET MAUI:
- Maui.IImage is the interface that abstracts the Image control.
- Maui.Graphics.IImage is used for image display, manipulation, and persistence when displaying graphics in a GraphicsView.
The image is retrieved from the assembly and loaded as a stream and is drawn at (10, 10) with its size:
using Microsoft.Maui.Graphics.Platform;
using IImage = Microsoft.Maui.Graphics.IImage;
using System.Reflection;
public void Draw(ICanvas canvas, RectF rectF)
{
IImage image;
Assembly assembly = GetType().GetTypeInfo().Assembly;
using (Stream stream = assembly.GetManifestResourceStream("Graphics.Resources.Images.image.png"))
{
image = PlatformImage.FromStream(stream);
}
if (image != null)
{
canvas.DrawImage(image, 10, 10, image.Width, image.Height);
}
}
Transforms
Translate: to shift graphical objects from one location to another.
public void Draw(ICanvas canvas, RectF rectF)
{
canvas.Translate(50, 50);
canvas.StrokeColor = Colors.Teal;
canvas.StrokeSize = 3;
canvas.DrawArc(0, 0, 100, 100, 0, 180, false, false);
// Translate transform is used to shift the arc to (200, 200):
canvas.FillColor = Colors.Red;
}
In figure, the left are not translate before draw arc at (0, 0), the right is translate to (50, 50) before draw it.
Scale: to increase or decrease coordinates and size by (x, y).
- If values x and y are between 0 and 1, the width and height of the scaled object decrease.
- If values x and y are greater than 1, the width and height of the scaled object increase.
- if values x, y of 1 indicate, the object is not scaled.
public void Draw(ICanvas canvas, RectF rectF)
{
canvas.StrokeColor = Colors.Red;
canvas.StrokeSize = 3;
canvas.StrokeDashPattern = new float[] { 2, 2 };
canvas.FontColor = Colors.Blue;
canvas.FontSize = 15;
canvas.DrawRoundedRectangle(60, 60, 80, 40, 5);
canvas.DrawString("ISB Vietnam", 60, 60, 80, 20, HorizontalAlignment.Left, VerticalAlignment.Top);
canvas.Scale(2, 2);
canvas.DrawRoundedRectangle(60, 100, 80, 40, 5);
canvas.DrawString("ISB Vietnam", 60, 100, 80, 20, HorizontalAlignment.Left, VerticalAlignment.Top);
}
The result:
Rotate: to rotate graphical objects around a point with an angle degree.
public void Draw(ICanvas canvas, RectF rectF)
{
canvas.FontColor = Colors.Black;
canvas.FontSize = 15;
// rotate 60 degrees
canvas.Rotate(60, rectF.Center.X, rectF.Center.Y);
canvas.DrawString("ISB Vietnam", rectF.Center.X, rectF.Center.Y, HorizontalAlignment.Left);
}
The result:
Summary
In this blog I show how to use GraphicsView canvas to draw graphical objects in .NET MAUI.
It is necessary to create a class that derives from IDrawable interface and implement Draw method.
All graphical objects are drawn in this method by an ICanvas instance.
Reference
[1]. https://learn.microsoft.com/en-us/dotnet/maui/user-interface/graphics/?view=net-maui-8.0
[2]. https://www.syncfusion.com/blogs/post/draw-2d-graphics-in-dotnet-maui-graphicsview.aspx
[3]. https://www.youtube.com/playlist?list=PLdo4fOcmZ0oUBAdL2NwBpDs32zwGqb9DY. James Montemagno
[4]. https://dotnet.microsoft.com/en-us/apps/maui
[5]. https://www.flaticon.com/free-icon/responsive-design_4661538