.NET MAUI у 2026 році: кросплатформна розробка та питання для співбесід

Повний посібник з .NET MAUI 10 у 2026 році: налаштування проєкту, архітектура Handlers, MVVM, HybridWebView та найпоширеніші питання для технічних співбесід.

.NET MAUI cross-platform development tutorial 2026

.NET MAUI (Multi-platform App UI) утвердився як основний фреймворк для створення нативних застосунків під Android, iOS, macOS та Windows з єдиної кодової бази на C#. З випуском .NET 10 як версії з довготривалою підтримкою (LTS, до листопада 2028 року), MAUI 10 зосередився на якості, продуктивності та нових API, таких як HybridWebView та SafeAreaEdges. Цей посібник охоплює створення кросплатформного застосунку, архітектуру фреймворка та питання, які ставлять на технічних співбесідах у 2026 році.

.NET MAUI 10 LTS

.NET 10 — це реліз з довготривалою підтримкою (до листопада 2028 року). MAUI 10 фокусується на якості та продуктивності, а не на нових UI-контролах, що робить його найстабільнішим релізом MAUI. Тепер він розповсюджується як workload .NET та NuGet-пакети, що дозволяє фіксувати версію для кожного проєкту.

Налаштування проєкту .NET MAUI 10 з нуля

Найшвидший шлях до працюючого застосунку MAUI починається з .NET CLI. .NET 10 пропонує оновлений шаблон проєкту, який включає підтримку .NET Aspire для телеметрії та виявлення сервісів.

bash
# Install the MAUI workload (if not already present)
dotnet workload install maui

# Create a new MAUI app
dotnet new maui -n CrossPlatformDemo
cd CrossPlatformDemo

# Run on Android emulator
dotnet build -t:Run -f net10.0-android

Структура єдиного проєкту консолідує платформо-специфічний код у каталозі Platforms/, розділяючи спільний код. Файл MauiProgram.cs виконує роль composition root — саме тут реєструються сервіси, шрифти та хендлери.

MauiProgram.cscsharp
using Microsoft.Extensions.Logging;

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
            });

        // Register services for dependency injection
        builder.Services.AddSingleton<IApiService, ApiService>();
        builder.Services.AddTransient<MainViewModel>();

#if DEBUG
        builder.Logging.AddDebug();
#endif

        return builder.Build();
    }
}

Dependency injection у MAUI використовує той самий патерн, що й ASP.NET Core. Singleton-сервіси існують протягом усього життєвого циклу застосунку, Transient-сервіси створюються при кожному запиті, а Scoped-сервіси — хоча й доступні — потребують обережності, оскільки MAUI не має вбудованої концепції scope, як HTTP-запити.

Хендлери: архітектура кросплатформного рендерингу

MAUI замінив рендерери Xamarin.Forms на архітектуру хендлерів. Хендлери відображають кожен кросплатформний елемент управління на його нативний аналог через тонкий шар абстракції. Ключова відмінність полягає в тому, що хендлери є stateless та відокремлені від віртуального представлення, що робить їх швидшими та легшими для кастомізації.

CustomEntryHandler.cs — Customizing the Entry control on Androidcsharp
using Microsoft.Maui.Handlers;

public class CustomEntryHandler : EntryHandler
{
    protected override void ConnectHandler(MauiAppCompatEditText platformView)
    {
        base.ConnectHandler(platformView);
        // Remove the default underline on Android
        platformView.SetBackgroundColor(Android.Graphics.Color.Transparent);
    }
}

// Register in MauiProgram.cs
builder.ConfigureMauiHandlers(handlers =>
{
    handlers.AddHandler<Entry, CustomEntryHandler>();
});

У .NET 10 контроли Entry та Editor на Android перейшли з AppCompatEditText на MauiAppCompatEditText, додавши нативну підтримку події SelectionChanged. Покращені хендлери CollectionView та CarouselView, представлені у .NET 9, тепер використовуються за замовчуванням на iOS та Mac Catalyst.

MVVM з CommunityToolkit.Mvvm: усунення шаблонного коду

Генератор вихідного коду CommunityToolkit.Mvvm усуває приблизно 80% церемоніального коду MVVM. Жодної ручної реалізації INotifyPropertyChanged, жодних обгорток команд — атрибути керують генерацією коду.

MainViewModel.cscsharp
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;

public partial class MainViewModel : ObservableObject
{
    private readonly IApiService _apiService;

    public MainViewModel(IApiService apiService)
    {
        _apiService = apiService;
    }

    // Source generator creates the 'Title' property with change notification
    [ObservableProperty]
    private string _title = string.Empty;

    // Source generator creates the 'IsLoading' property
    [ObservableProperty]
    private bool _isLoading;

    // Source generator creates an async ICommand
    [RelayCommand]
    private async Task LoadDataAsync()
    {
        IsLoading = true;
        try
        {
            Title = await _apiService.FetchTitleAsync();
        }
        finally
        {
            IsLoading = false;
        }
    }
}

XAML прив'язується безпосередньо до згенерованих властивостей та команд:

xml
<!-- MainPage.xaml -->
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:vm="clr-namespace:CrossPlatformDemo.ViewModels"
             x:DataType="vm:MainViewModel">
    <VerticalStackLayout Padding="20" Spacing="16">
        <Label Text="{Binding Title}"
               FontSize="24"
               HorizontalOptions="Center" />
        <Button Text="Load Data"
                Command="{Binding LoadDataCommand}"
                IsEnabled="{Binding IsLoading, Converter={StaticResource InverseBoolConverter}}" />
        <ActivityIndicator IsRunning="{Binding IsLoading}"
                           IsVisible="{Binding IsLoading}" />
    </VerticalStackLayout>
</ContentPage>

Атрибут x:DataType вмикає компільовані прив'язки, які працюють швидше за прив'язки на основі рефлексії та генерують помилки компіляції, коли шлях прив'язки некоректний.

Готовий до співбесід з .NET?

Практикуйся з нашими інтерактивними симуляторами, flashcards та технічними тестами.

HybridWebView у .NET 10: поєднання нативного та веб

HybridWebView дозволяє вбудовувати веб-контент у застосунок MAUI, забезпечуючи двосторонню комунікацію між C# та JavaScript. .NET 10 додає три можливості: виклики JavaScript типу fire-and-forget, події ініціалізації для платформо-специфічної конфігурації та перехоплення веб-запитів.

MainPage.xaml.cs — HybridWebView interactioncsharp
public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();

        // Initialization event for platform-specific tweaks
        hybridWebView.WebViewInitialized += (sender, args) =>
        {
            // Access the native platform view after initialization
            System.Diagnostics.Debug.WriteLine("WebView ready");
        };
    }

    // Call JavaScript from C#
    private async void OnCallJsClicked(object sender, EventArgs e)
    {
        var result = await hybridWebView.InvokeJavaScriptAsync<string>(
            "getFormData",  // JS function name
            HybridSampleContext.Default.String  // JSON serialization context
        );
        await DisplayAlert("Result", result, "OK");
    }

    // Fire-and-forget: no return type needed (.NET 10)
    private async void OnResetClicked(object sender, EventArgs e)
    {
        await hybridWebView.InvokeJavaScriptAsync("resetForm");
    }
}

Відповідний JavaScript отримує виклики та може надсилати повідомлення назад до C#:

wwwroot/index.html (HybridWebView content)javascript
function getFormData() {
    return JSON.stringify({
        name: document.getElementById('name').value,
        email: document.getElementById('email').value
    });
}

function resetForm() {
    document.getElementById('name').value = '';
    document.getElementById('email').value = '';
}

Винятки JavaScript, кинуті під час InvokeJavaScriptAsync, тепер автоматично передаються до .NET як виключення, усуваючи тихі збої.

SafeAreaEdges: ідеальні макети на кожному пристрої

.NET MAUI 10 вводить властивість SafeAreaEdges для Layout, ContentView, ContentPage, Border та ScrollView. Новий enum (None, SoftInput, Container, Default, All) замінює застарілий iOS-специфічний Page.UseSafeArea кросплатформним підходом.

xml
<!-- Granular safe area control per section -->
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             SafeAreaEdges="All">
    <Grid RowDefinitions="Auto,*,Auto">
        <!-- Header respects all safe areas -->
        <Border Grid.Row="0" SafeAreaEdges="Container">
            <Label Text="Header" />
        </Border>

        <!-- Content scrolls under safe areas -->
        <ScrollView Grid.Row="1" SafeAreaEdges="SoftInput">
            <VerticalStackLayout Padding="16">
                <Entry Placeholder="Type here..." />
            </VerticalStackLayout>
        </ScrollView>

        <!-- Footer avoids home indicator -->
        <Border Grid.Row="2" SafeAreaEdges="Container">
            <Label Text="Footer" />
        </Border>
    </Grid>
</ContentPage>

SoftInput коригує контент при появі екранної клавіатури. Container уникає вирізів, корпусів сенсорів та індикатора home. Ці значення можна комбінувати для кожного елемента управління.

Міграція з Xamarin.Forms на .NET MAUI

Підтримка Xamarin.Forms завершилась у травні 2024 року. Міграція на MAUI вимагає структурних змін, що виходять за межі простої заміни просторів імен.

Кінець підтримки Xamarin

Xamarin.Forms не отримує підтримки з травня 2024 року. Застосунки, що досі працюють на Xamarin, несуть ризики безпеки та сумісності. .NET MAUI 10 (LTS, підтримка до листопада 2028) є визначеним цільовим фреймворком для міграції.

  1. Структура проєкту — конвертація з платформо-специфічних проєктів у модель єдиного проєкту MAUI. Перенесення спільного коду до кореня, платформного коду — до Platforms/.
  2. Простори імен — заміна Xamarin.Forms на Microsoft.Maui.Controls та Xamarin.Essentials на Microsoft.Maui.Essentials (тепер вбудовано у MAUI).
  3. Рендерери на хендлери — кастомні рендерери мають бути переписані як хендлери. API хендлерів простіше, але логіка маппінгу відрізняється.
  4. Ініціалізація — заміна ініціалізації App.xaml.cs на патерн builder у MauiProgram.cs.
  5. NuGet-пакети — багато пакетів ери Xamarin мають MAUI-еквіваленти. Необхідно перевірити сумісність перед оновленням.
  6. Dependency injection — MAUI нативно використовує Microsoft.Extensions.DependencyInjection. Заміна будь-яких сторонніх DI-контейнерів або викликів DependencyService.

Найпоширеніші питання для співбесід з .NET MAUI у 2026 році

Ці питання відображають те, що запитують команди з найму у 2026 році, базуючись на поточній екосистемі .NET 10.

Чим архітектура хендлерів MAUI відрізняється від рендерерів Xamarin.Forms?

Рендерери у Xamarin.Forms були тісно пов'язані як з кросплатформним контролом, так і з нативним представленням, створюючи двосторонню залежність. Хендлери у MAUI є stateless-маперами: вони отримують сповіщення про зміну властивостей та застосовують їх до нативного представлення через словник маперів. Це розділення спрощує тестування, розширення та повторне використання хендлерів. Словники PropertyMapper та CommandMapper замінюють патерн перевизначення OnElementPropertyChanged, роблячи кастомізацію явною.

Які підводні камені DI lifetime специфічні для MAUI?

MAUI підтримує Singleton, Transient та Scoped lifetime, але Scoped поводиться інакше, ніж у ASP.NET Core. Природної межі scope (як HTTP-запит) не існує. Поширені помилки: реєстрація ViewModel як Singleton, коли він зберігає стан конкретної сторінки (застарілі дані при навігації), або реєстрація з'єднання з базою даних як Transient (вичерпання пулу з'єднань).

Порада для співбесіди

Відповідаючи на питання про DI, важливо продемонструвати розуміння відмінностей життєвого циклу MAUI від request-scoped моделі ASP.NET Core. Інтерв'юери шукають обізнаність щодо витоків пам'яті та проблем із застарілим станом, специфічних для довготривалих мобільних застосунків.

Чим компільовані прив'язки відрізняються від прив'язок на основі рефлексії?

Прив'язки на основі рефлексії розв'язують шляхи властивостей під час виконання за допомогою System.Reflection, що є повільним та генерує помилки часу виконання при друкарських помилках. Компільовані прив'язки, увімкнені через x:DataType, розв'язують шляхи прив'язок під час компіляції. Компілятор генерує код прямого доступу до властивостей, повністю обходячи рефлексію. Це покращує час запуску, зменшує алокації пам'яті та виявляє помилки прив'язок під час збирання.

Які стратегії існують для спільного використання коду між застосунком MAUI та бекендом ASP.NET Core?

Рекомендований підхід використовує спільну бібліотеку класів, що містить DTO, логіку валідації та бізнес-правила. І застосунок MAUI, і бекенд ASP.NET Core посилаються на цю бібліотеку. .NET 10 підсилює цей патерн інтеграцією .NET Aspire для MAUI, забезпечуючи виявлення сервісів та телеметрію між мобільними та бекенд-проєктами. Спільні контракти з використанням генераторів System.Text.Json забезпечують консистентність серіалізації.

Чим HybridWebView відрізняється від BlazorWebView у MAUI?

BlazorWebView хостить повний застосунок Blazor всередині застосунку MAUI. Razor-компоненти рендеряться у вбудований WebView, але .NET runtime виконується нативно (не через WebAssembly). HybridWebView є легшим: він завантажує статичний HTML/CSS/JS контент та забезпечує інтероп C#-JavaScript без накладних витрат фреймворка Blazor. Вибір залежить від сценарію використання. BlazorWebView підходить командам з існуючими Blazor-компонентами, які хочуть повторного використання коду. HybridWebView підходить для сценаріїв, де існуючий веб-контент потребує нативної інтеграції без повного фреймворка.

Починай практикувати!

Перевір свої знання з нашими симуляторами співбесід та технічними тестами.

Висновок

  • .NET MAUI 10 — це LTS-реліз (підтримка до листопада 2028), зосереджений на стабільності та продуктивності, що робить його надійним вибором для виробничих кросплатформних застосунків
  • Архітектура хендлерів замінює рендерери Xamarin stateless-маперами, покращуючи тестування та кастомізацію через PropertyMapper та CommandMapper
  • Генератори вихідного коду CommunityToolkit.Mvvm усувають більшість шаблонного коду MVVM — атрибути [ObservableProperty] та [RelayCommand] замінюють ручні реалізації
  • HybridWebView у .NET 10 додає fire-and-forget виклики JavaScript, події ініціалізації та перехоплення запитів для нативно-веб інтеграції
  • SafeAreaEdges забезпечує гранулярний, кросплатформний контроль над вирізами пристроїв, клавіатурами та системними панелями
  • Міграція з Xamarin.Forms вимагає переписування хендлерів та рефакторингу ініціалізації
  • Підготовка до співбесід має фокусуватися на архітектурі хендлерів vs. рендерерів, підводних каменях DI, компільованих прив'язках та компромісах HybridWebView vs. BlazorWebView

Починай практикувати!

Перевір свої знання з нашими симуляторами співбесід та технічними тестами.

Теги

#dotnet
#maui
#cross-platform
#xamarin
#mobile

Поділитися

Пов'язані статті