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

Посібник .NET MAUI, що охоплює кросплатформну розробку з .NET 10, хендлери, MVVM, HybridWebView та ключові питання для співбесід 2026 року.

.NET MAUI cross-platform development tutorial 2026

.NET MAUI (Multi-platform App UI) став повноцінним production-ready кросплатформним фреймворком з виходом .NET 10. Випущений як версія з довготривалою підтримкою (LTS, до листопада 2028 року), .NET MAUI 10 поставляється як workload та NuGet-пакети, забезпечуючи покращену якість, продуктивність та нові API, такі як розширення HybridWebView і SafeAreaEdges. Цей посібник охоплює створення кросплатформного застосунку, архітектуру, що стоїть за MAUI, та питання співбесід, які задають менеджери з найму у 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.cscsharp
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, вирішуючи тривалі проблеми зі стабільністю.

Android 16 Edge-to-Edge: критична зміна та необхідне виправлення

Android 16 видаляє механізм відмови від edge-to-edge відображення. Застосунки, що цілять на API 36, повинні правильно обробляти відступи системних панелей, інакше контент рендериться некоректно. .NET 10 ввів тиху критичну зміну: у .NET 9 ContentPage за замовчуванням поважав системні панелі (поведінка Container), але .NET 10 за замовчуванням використовує edge-to-edge (None).

Критична зміна в .NET 10

Застосунки, що мігрують з .NET 9 до .NET 10, можуть побачити, що контент рендериться під рядком стану або навігаційною панеллю на Android 15+. Виправлення вимагає явного встановлення SafeAreaEdges для відновлення попередньої поведінки.

Виправлення полягає у додаванні глобального неявного стилю до App.xaml:

xml
<!-- App.xaml -->
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CrossPlatformDemo.App">
    <Application.Resources>
        <ResourceDictionary>
            <Style TargetType="ContentPage" ApplyToDerivedTypes="True">
                <Setter Property="SafeAreaEdges" Value="Container" />
            </Style>
        </ResourceDictionary>
    </Application.Resources>
</Application>

Enum SafeAreaEdges забезпечує гранулярний контроль:

  • None: edge-to-edge контент без відступу safe area
  • SoftInput: завжди додавати відступ для клавіатури
  • Container: плити під клавіатурою, уникати панелей та вирізу
  • Default: поведінка платформи за замовчуванням
  • All: поважати всі відступи safe area

Цей підхід використовує Window Insets API під час виконання, що робить його сумісним з Android 16, де відмови на рівні маніфесту більше не працюють.

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 та технічними тестами.

Генератор XAML Source у .NET 10

.NET MAUI 10 представляє генератор XAML source, який компілює XAML під час збирання, а не парсить його під час виконання. Це покращує продуктивність запуску та виявляє помилки XAML під час компіляції.

Щоб увімкнути генерацію XAML source, додайте властивість до файлу проєкту:

xml
<PropertyGroup>
  <MauiXamlInflator>SourceGen</MauiXamlInflator>
</PropertyGroup>

.NET 10 Preview 5 також представив неявні простори імен XML, які усувають шаблонні оголошення xmlns. Файл GlobalXmlns.cs може агрегувати кілька просторів імен:

GlobalXmlns.cscsharp
[assembly: XmlnsDefinition(
    "http://schemas.microsoft.com/dotnet/maui/global",
    "MyApp.Views")]
[assembly: XmlnsDefinition(
    "http://schemas.microsoft.com/dotnet/maui/global",
    "MyApp.Controls")]

З цим налаштуванням файли XAML стають чистішими:

xml
<!-- До -->
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        xmlns:controls="clr-namespace:MyApp.Controls"
        x:Class="MyApp.MainPage">
    <controls:TagView />
</ContentPage>

<!-- Після (з глобальним xmlns) -->
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/maui/global"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyApp.MainPage">
    <TagView />
</ContentPage>

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

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

MainPage.xaml.cscsharp
public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();

        // Initialization event for platform-specific tweaks
        hybridWebView.WebViewInitialized += (sender, args) =>
        {
            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",
            HybridSampleContext.Default.String
        );
        await DisplayAlertAsync("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, кинуті під час InvokeJavaScriptAsync, тепер автоматично передаються до .NET як виключення, усуваючи тихі збої. Перехоплення веб-запитів дозволяє модифікувати заголовки або надавати локальні відповіді:

csharp
webView.WebResourceRequested += (s, e) =>
{
    if (e.Uri.ToString().Contains("api/secure"))
    {
        e.Handled = true;
        e.SetResponse(200, "OK", "application/json", GetCustomStream());
    }
};

Застарілі API та шлях міграції

.NET MAUI 10 позначає кілька API як застарілі. Застосунки, що використовують ці елементи, повинні мігрувати до рекомендованих альтернатив.

ListView та пов'язані комірки: ListView, EntryCell, ImageCell, SwitchCell, TextCell та ViewCell є застарілими. Використовуйте CollectionView, який має кращу продуктивність та стабільність з новими хендлерами iOS/Mac Catalyst.

MessagingCenter: Зроблено внутрішнім у .NET 10. Замініть на WeakReferenceMessenger з CommunityToolkit.Mvvm.

Методи анімації: FadeTo, RotateTo, ScaleTo та подібні методи є застарілими. Використовуйте асинхронні еквіваленти: FadeToAsync, RotateToAsync, ScaleToAsync.

TableView: Застарілий на користь CollectionView.

DisplayAlert/DisplayActionSheet: Замінено на DisplayAlertAsync та DisplayActionSheetAsync.

Міграція з 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 Upgrade Assistant автоматизує частини кроків 1-2, але хендлери (крок 3) та налаштування бізнес-логіки потребують ручної роботи.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Практикуйте більше питань співбесід .NET на SharpSkill, щоб закріпити ці концепції інтерактивними вправами.

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

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

Джерела

Що повинні пам'ятати розробники .NET MAUI 10

  • .NET MAUI 10 — це LTS-реліз (підтримка до листопада 2028), зосереджений на стабільності та продуктивності, що робить його надійним вибором для виробничих кросплатформних застосунків
  • Android 16 робить edge-to-edge обов'язковим: додайте SafeAreaEdges="Container" як глобальний стиль у App.xaml, щоб відновити поведінку .NET 9
  • Генератор XAML source (MauiXamlInflator=SourceGen) компілює XAML під час збирання, покращуючи продуктивність запуску та виявляючи помилки раніше
  • ListView, TableView та MessagingCenter є застарілими: мігруйте до CollectionView та WeakReferenceMessenger
  • Архітектура хендлерів замінює рендерери Xamarin stateless-маперами, покращуючи тестування через PropertyMapper та CommandMapper
  • Генератори вихідного коду CommunityToolkit.Mvvm усувають більшість шаблонного коду MVVM: атрибути [ObservableProperty] та [RelayCommand] замінюють ручні реалізації
  • HybridWebView у .NET 10 додає fire-and-forget виклики JavaScript, події ініціалізації та перехоплення запитів для нативно-веб інтеграції
  • Підготовка до співбесід має фокусуватися на архітектурі хендлерів vs. рендерерів, підводних каменях DI в довготривалих застосунках, компільованих прив'язках та компромісах HybridWebView vs. BlazorWebView
Щоденний виклик

Чи знайдеш ти помилку в .NET?

Справжній фрагмент коду, прихована помилка, одна спроба на день. Щоб спробувати, акаунт не потрібен.

Anthony Fillion-Maillet

Автор:

Anthony Fillion-Maillet

Засновник SharpSkill

Fullstack-розробник понад 10 років. Керує SharpSkill і відповідає за все, що тут публікується.

Оновлено 14 вересня 2026 р.

Теги

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

Поділитися

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