What you will learn

  • Use Grid to organize operation buttons
  • Read and validate numeric input
  • Handle division by zero without an exception
How to use this example: Start from a new .NET MAUI App project called MauiCalculator with .NET 10. Use the complete file listings below, and leave other template-generated files unchanged unless the lesson explicitly says otherwise. Run the Android target on Windows.

1. Create the calculator project

Create a .NET MAUI App named MauiCalculator. Replace the MainPage XAML and code-behind using the exact code below. This lesson deliberately uses code-behind so you can focus on input validation and a working mini-project.

2. Understand the calculation logic

The four buttons share one Clicked event. Their CommandParameter values identify the operation. double.TryParse avoids exceptions when the user enters invalid input, and the division branch checks for a zero divisor.

3. Run systematic tests

FirstSecondOperationExpected
105+15
105−5
105×50
105÷2
100÷Error message

4. Adapt for a polished app

Consider a Clear button, operation history, and decimal rounding preferences. In a larger app, calculation code should be moved into a separate service or ViewModel and covered by automated unit tests.

Complete sample code

Use the exact file names and folder locations shown below. Copy each listing into your MAUI project. The separate source files can also be downloaded individually.

MainPage.xaml
<?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"
             x:Class="MauiCalculator.MainPage"
             Title="Calculator">
    <VerticalStackLayout Padding="24" Spacing="16">
        <Label Text="Two-Number Calculator"
               FontSize="26" FontAttributes="Bold" />
        <Entry x:Name="FirstEntry" Placeholder="First number"
               Keyboard="Numeric" />
        <Entry x:Name="SecondEntry" Placeholder="Second number"
               Keyboard="Numeric" />
        <Grid ColumnDefinitions="*,*,*,*" ColumnSpacing="8">
            <Button Text="+" CommandParameter="+"
                    Clicked="OnCalculateClicked" />
            <Button Grid.Column="1" Text="−" CommandParameter="-"
                    Clicked="OnCalculateClicked" />
            <Button Grid.Column="2" Text="×" CommandParameter="*"
                    Clicked="OnCalculateClicked" />
            <Button Grid.Column="3" Text="÷" CommandParameter="/"
                    Clicked="OnCalculateClicked" />
        </Grid>
        <Label x:Name="ResultLabel" Text="Enter two numbers."
               FontSize="20" />
    </VerticalStackLayout>
</ContentPage>
MainPage.xaml.cs
using System.Globalization;

namespace MauiCalculator;

public partial class MainPage : ContentPage
{
    public MainPage() => InitializeComponent();

    private void OnCalculateClicked(object sender, EventArgs e)
    {
        if (!double.TryParse(FirstEntry.Text, NumberStyles.Float,
                             CultureInfo.CurrentCulture, out double a) ||
            !double.TryParse(SecondEntry.Text, NumberStyles.Float,
                             CultureInfo.CurrentCulture, out double b))
        {
            ResultLabel.Text = "Enter two valid numbers.";
            return;
        }

        string op = (sender as Button)?.CommandParameter?.ToString() ?? "";
        if (op == "/" && b == 0)
        {
            ResultLabel.Text = "Cannot divide by zero.";
            return;
        }

        double answer = op switch
        {
            "+" => a + b,
            "-" => a - b,
            "*" => a * b,
            "/" => a / b,
            _ => double.NaN
        };
        ResultLabel.Text = $"Result: {answer:0.##}";
    }
}

Common problems and solutions

  • A decimal number is rejected: The current device culture determines whether a comma or period is used as decimal separator.
  • Result is not updated: Check the button Clicked handler and CommandParameter values.

Practice exercise

Add a Clear button that empties both Entry controls and resets the result label.

Expected result: All four operations calculate correctly, with friendly invalid-input messages.