.NET MAUI 10: دليلك الشامل للميزات الجديدة وخطوات الترقية العملية

دليل عملي شامل حول .NET MAUI 10 يغطي XAML Source Generation وCollectionView والتكامل مع .NET Aspire وNativeAOT، مع خطوات ترقية من .NET 9 وأمثلة كود جاهزة للتطبيق.

إذا كنت مطور تطبيقات متعددة المنصات، فالأغلب أنك سمعت بالفعل عن .NET MAUI 10. صراحةً، هذا الإصدار يستحق الاهتمام فعلاً. ليس لأنه يضيف مئات الميزات الجديدة اللامعة، بل لأنه يركز على شيء أهم بكثير: الجودة وتجربة المطور. باعتباره إصدار LTS (أي دعم طويل الأمد لثلاث سنوات)، يُعتبر .NET 10 الخيار المثالي للمشاريع الإنتاجية والتجارية. ومن أبرز ما جاء فيه ميزة XAML Source Generation التي — وهذا ليس مبالغة — تُسرّع تحميل واجهات المستخدم بمقدار 100 مرة في بيئة التطوير!

فلنبدأ معاً في استكشاف كل ما يقدمه هذا الإصدار.

نظرة عامة على .NET MAUI 10

.NET MAUI 10 جزء من منصة .NET 10 التي أُطلقت في نوفمبر 2025. ما يميزه عن الإصدارات السابقة هو فلسفته المختلفة تماماً: بدلاً من إضافة ميزات بشكل مكثف، اختار الفريق التركيز على "الجودة أولاً". تم حل آلاف المشكلات المفتوحة، وتحسين الأداء بشكل ملحوظ، وتوفير أدوات أفضل للمطورين.

بصراحة، هذا كان مطلوباً منذ فترة طويلة.

من الناحية العملية، أصبحت التطبيقات تعمل بسلاسة أكبر على جميع المنصات المدعومة: iOS، Android، macOS، وWindows. كما تحسنت تجربة التطوير في Visual Studio وVisual Studio Code، مع دعم أفضل لـ Hot Reload وتصحيح الأخطاء.

XAML Source Generation: الميزة التي غيّرت قواعد اللعبة

هذه الميزة بالذات هي التي جعلتني متحمساً أكثر شيء في هذا الإصدار. الفكرة ببساطة: بدلاً من أن تُحلَّل ملفات XAML وتُفسَّر أثناء التشغيل (Runtime) باستخدام الانعكاس (Reflection) — وهو ما كان يسبب بطءاً ملحوظاً — أصبح الآن يتم توليد كود C# مباشرةً من ملفات XAML وقت الترجمة (Compile-time).

النتيجة؟ تحسينات أداء مذهلة.

كيفية تفعيل XAML Source Generation

عندك طريقتين. الأولى هي تفعيلها على مستوى المشروع بالكامل بإضافة هذا في ملف .csproj:

<PropertyGroup>
  <TargetFrameworks>net10.0-android;net10.0-ios;net10.0-maccatalyst</TargetFrameworks>
  <MauiXamlInflator>SourceGen</MauiXamlInflator>
</PropertyGroup>

أما الطريقة الثانية فهي تفعيلها لملفات محددة فقط — وهذا مفيد جداً لو تريد الترقية التدريجية أو عندك ملفات XAML معقدة تحتاج اختبار إضافي:

<ItemGroup>
  <MauiXaml Update="Views/**/*.xaml" Inflator="SourceGen" />
  <MauiXaml Update="Controls/**/*.xaml" Inflator="SourceGen" />
</ItemGroup>

الفوائد الأساسية

دعني ألخص لك لماذا هذه الميزة "إلزامية" تقريباً لأي مشروع جديد:

  • سرعة فائقة في بيئة التطوير: تحسن بمعدل 100 مرة في سرعة تحميل XAML عند التشغيل بوضع Debug — يعني فتح الصفحات يصير شبه فوري
  • تحسين أداء الإنتاج: تسريع بنسبة 25% في وضع Release
  • إمكانية تصحيح XAML: لأول مرة تقدر تحط Breakpoints في الكود المولّد من XAML وتشوف كيف تُنشأ العناصر
  • اتساق بين Debug وRelease: نفس آلية المعالجة في كلا الوضعين، فلا مفاجآت عند النشر
  • أخطاء واضحة وقت الترجمة: اكتشاف الأخطاء في XAML أثناء البناء بدلاً من وقت التشغيل

عرض الملفات المولّدة

من الأشياء الممتعة إنك تقدر تشوف الكود اللي تم توليده. عند تفعيل XAML Source Generation، تُنشأ ملفات بامتداد .xsg في مجلد obj. لعرضها في Visual Studio:

  1. افتح Solution Explorer
  2. فعّل خيار "Show All Files"
  3. انتقل إلى obj/Debug/net10.0-android/ (أو المنصة المستهدفة)
  4. ابحث عن ملفات .xsg التي تحمل نفس أسماء ملفات XAML

مثال على الكود المولّد من ملف XAML بسيط:

// Auto-generated code from MainPage.xaml
partial class MainPage
{
    private void InitializeComponent()
    {
        var nameScope = new Microsoft.Maui.Controls.Internals.NameScope();
        Microsoft.Maui.Controls.NameScope.SetNameScope(this, nameScope);

        var label = new Microsoft.Maui.Controls.Label();
        label.Text = "Hello, .NET MAUI 10!";
        label.FontSize = 24;
        label.HorizontalOptions = Microsoft.Maui.Controls.LayoutOptions.Center;
        label.VerticalOptions = Microsoft.Maui.Controls.LayoutOptions.Center;

        this.Content = label;
    }
}

CollectionView كـ Handler افتراضي

خطوة كانت متوقعة بصراحة. أصبح CollectionView وCarouselView يستخدمان المعالجات (Handlers) المحسنة افتراضياً في .NET MAUI 10. هذه المعالجات طُورت في .NET 9 وأثبتت كفاءتها. في المقابل، تم إهمال (Deprecate) كل من ListView وTableView — ما يعني إنك لازم تبدأ تخطط للانتقال إلى CollectionView.

لماذا تم إهمال ListView؟

ListView كان رفيق الدرب لعرض القوائم من أيام Xamarin.Forms، لكنه صار يعاني من مشاكل حقيقية:

  • أداء ضعيف مع القوائم الكبيرة
  • مرونة محدودة في تخصيص التخطيطات
  • صعوبة في السيناريوهات المعقدة مثل التحديد المتعدد
  • كود قديم صعب الصيانة (وهذا وحده سبب كافي)

CollectionView حل كل هذه المشاكل وأكثر.

الانتقال من ListView إلى CollectionView

لنشوف مثال عملي. هذا كود ListView التقليدي:

<ListView ItemsSource="{Binding Products}"
          ItemSelected="OnProductSelected"
          HasUnevenRows="True">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <StackLayout Padding="10">
                    <Label Text="{Binding Name}"
                           FontSize="18"
                           FontAttributes="Bold" />
                    <Label Text="{Binding Description}"
                           FontSize="14"
                           TextColor="Gray" />
                    <Label Text="{Binding Price, StringFormat='{0:C}'}"
                           FontSize="16"
                           TextColor="Green" />
                </StackLayout>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

والآن الكود المكافئ باستخدام CollectionView (لاحظ كيف إنه أبسط — ما تحتاج ViewCell):

<CollectionView ItemsSource="{Binding Products}"
                SelectionMode="Single"
                SelectionChanged="OnProductSelectionChanged">
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <StackLayout Padding="10">
                <Label Text="{Binding Name}"
                       FontSize="18"
                       FontAttributes="Bold" />
                <Label Text="{Binding Description}"
                       FontSize="14"
                       TextColor="Gray" />
                <Label Text="{Binding Price, StringFormat='{0:C}'}"
                       FontSize="16"
                       TextColor="Green" />
            </StackLayout>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

تغيير معالجة الأحداث

من أهم الفروقات هو تغيير حدث التحديد. الكود القديم مع ListView:

private void OnProductSelected(object sender, SelectedItemChangedEventArgs e)
{
    if (e.SelectedItem is Product product)
    {
        Navigation.PushAsync(new ProductDetailPage(product));
        ((ListView)sender).SelectedItem = null;
    }
}

الكود الجديد مع CollectionView:

private void OnProductSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (e.CurrentSelection.FirstOrDefault() is Product product)
    {
        Navigation.PushAsync(new ProductDetailPage(product));
        ((CollectionView)sender).SelectedItem = null;
    }
}

مزايا إضافية في CollectionView

وفوق كل هذا، CollectionView يوفر ميزات ما كانت متوفرة أصلاً في ListView:

  • أوضاع تحديد متعددة: None, Single, Multiple
  • تخطيطات مرنة: Linear, Grid, Custom
  • Header وFooter مدمجان: بدون حلول ملتوية
  • EmptyView: عرض محتوى مخصص لما تكون القائمة فارغة
  • التمرير المبرمج: ScrollTo مع خيارات متقدمة
<CollectionView ItemsSource="{Binding Products}"
                SelectionMode="Multiple"
                SelectedItems="{Binding SelectedProducts}">
    <CollectionView.Header>
        <Label Text="Available Products"
               FontSize="20"
               Padding="15"
               BackgroundColor="LightBlue" />
    </CollectionView.Header>

    <CollectionView.EmptyView>
        <ContentView>
            <StackLayout HorizontalOptions="Center"
                        VerticalOptions="Center">
                <Label Text="No products available"
                       FontSize="18"
                       TextColor="Gray" />
                <Button Text="Refresh"
                        Command="{Binding RefreshCommand}" />
            </StackLayout>
        </ContentView>
    </CollectionView.EmptyView>

    <!-- ItemTemplate here -->
</CollectionView>

تحسينات عناصر التحكم

بالإضافة للميزات الرئيسية، جاء .NET MAUI 10 بتحسينات مهمة على عناصر التحكم الموجودة. خليني أعرض لك أبرزها.

CheckBox: أخيراً يدعم Command

أخيراً! أصبح بإمكان CheckBox الارتباط مباشرة بـ Commands في ViewModel، وهذا يسهّل تطبيق نمط MVVM بشكل نظيف:

<CheckBox IsChecked="{Binding IsAgreed}"
          Command="{Binding AcceptTermsCommand}"
          CommandParameter="{Binding TermsId}"
          Color="Green" />

في الـ ViewModel:

public class SettingsViewModel : BaseViewModel
{
    private bool _isAgreed;
    public bool IsAgreed
    {
        get => _isAgreed;
        set => SetProperty(ref _isAgreed, value);
    }

    public ICommand AcceptTermsCommand { get; }

    public SettingsViewModel()
    {
        AcceptTermsCommand = new Command<string>(async (termsId) =>
        {
            if (IsAgreed)
            {
                await LogTermsAcceptance(termsId);
                await ShowMessage("Thank you for accepting our terms!");
            }
        });
    }
}

Switch: خاصية OffColor الجديدة

شيء بسيط لكن كان ناقصاً. الآن تقدر تخصص لون Switch في كلا الحالتين:

<Switch IsToggled="{Binding IsNotificationsEnabled}"
        OnColor="Green"
        OffColor="Red"
        ThumbColor="White" />

MediaPicker: التحديد المتعدد وضغط الصور

MediaPicker تحسن بشكل كبير — أصبح يدعم اختيار ملفات متعددة وضغط الصور تلقائياً:

public async Task PickMultiplePhotosAsync()
{
    try
    {
        var options = new MediaPickerOptions
        {
            SelectionLimit = 5,
            CompressionQuality = 75
        };

        var results = await MediaPicker.PickMultiplePhotosAsync(options);

        if (results != null)
        {
            foreach (var result in results)
            {
                var stream = await result.OpenReadAsync();
                await UploadImage(stream, result.FileName);
            }
        }
    }
    catch (Exception ex)
    {
        await DisplayAlert("Error", ex.Message, "OK");
    }
}

WebView: اعتراض الطلبات

ميزة قوية جداً تسمح لك باعتراض وتعديل طلبات HTTP قبل إرسالها من WebView. تخيل إنك تقدر تضيف توكن المصادقة تلقائياً أو تحظر عناوين معينة:

<WebView Source="https://example.com"
         RequestIntercepting="OnRequestIntercepting" />
private void OnRequestIntercepting(object sender, WebViewRequestInterceptEventArgs e)
{
    // Add authentication header
    if (e.Request.Url.StartsWith("https://api.example.com"))
    {
        e.Request.Headers.Add("Authorization", $"Bearer {_authToken}");
    }

    // Block certain URLs
    if (e.Request.Url.Contains("ads."))
    {
        e.Cancel = true;
    }
}

Popover على iOS/Mac Catalyst

دعم محسّن لعرض Popover على منصات Apple:

public async Task ShowPopoverAsync()
{
    var popoverPage = new PopoverContentPage();

    await Navigation.PushModalAsync(popoverPage);

    if (DeviceInfo.Platform == DevicePlatform.iOS ||
        DeviceInfo.Platform == DevicePlatform.MacCatalyst)
    {
        if (popoverPage.Handler?.PlatformView is UIViewController controller)
        {
            controller.ModalPresentationStyle = UIModalPresentationStyle.Popover;

            var popover = controller.PopoverPresentationController;
            if (popover != null)
            {
                popover.SourceView = ((UIButton)sender).Handle;
                popover.PermittedArrowDirections = UIPopoverArrowDirection.Up;
            }
        }
    }
}

التكامل مع .NET Aspire

هنا الموضوع يصير مثيراً أكثر. .NET Aspire هو إطار عمل لبناء التطبيقات السحابية الموزعة، والآن يمكن دمجه مباشرة مع تطبيقات .NET MAUI.

ما هو .NET Aspire باختصار؟

هو مجموعة أدوات ومكتبات تسهّل بناء التطبيقات الموزعة:

  • Service Discovery: اكتشاف الخدمات تلقائياً
  • Telemetry: جمع بيانات القياس عن بعد
  • Resilience: إعادة المحاولة التلقائية ومعالجة الأخطاء
  • Health Checks: فحص صحة الخدمات
  • Configuration: إدارة الإعدادات بشكل مركزي

إنشاء مشروع MAUI مع Aspire

يمكنك إنشاء مشروع جديد باستخدام القالب المخصص:

dotnet new maui-aspire-servicedefaults -n MyMauiApp

أو إضافة Aspire لمشروع موجود:

dotnet add package Aspire.Microsoft.Maui.ServiceDefaults

تكوين Aspire في MauiProgram.cs

إليك مثال كامل على الإعداد:

using Microsoft.Extensions.DependencyInjection;
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");
            });

        // Add Aspire Service Defaults
        builder.Services.AddServiceDefaults();

        // Configure HTTP client with service discovery
        builder.Services.AddHttpClient("ProductsAPI", client =>
        {
            client.BaseAddress = new Uri("https+http://productsapi");
        })
        .AddStandardResilienceHandler();

        // Add telemetry
        builder.Services.AddOpenTelemetry()
            .WithTracing(tracing =>
            {
                tracing.AddSource("MyMauiApp");
                tracing.AddHttpClientInstrumentation();
            })
            .WithMetrics(metrics =>
            {
                metrics.AddHttpClientInstrumentation();
            });

        builder.Services.AddSingleton<IProductService, ProductService>();
        builder.Services.AddTransient<MainPage>();

        return builder.Build();
    }
}

استخدام HTTP Client مع Aspire

في الخدمة، تستخدم IHttpClientFactory للحصول على Client مهيأ بكل مميزات Aspire:

public class ProductService : IProductService
{
    private readonly HttpClient _httpClient;
    private readonly ILogger<ProductService> _logger;

    public ProductService(IHttpClientFactory httpClientFactory,
                         ILogger<ProductService> logger)
    {
        _httpClient = httpClientFactory.CreateClient("ProductsAPI");
        _logger = logger;
    }

    public async Task<List<Product>> GetProductsAsync()
    {
        try
        {
            _logger.LogInformation("Fetching products from API");

            var response = await _httpClient.GetAsync("/api/products");
            response.EnsureSuccessStatusCode();

            var products = await response.Content
                .ReadFromJsonAsync<List<Product>>();

            _logger.LogInformation("Retrieved {Count} products", products?.Count ?? 0);

            return products ?? new List<Product>();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error fetching products");
            throw;
        }
    }
}

Dev Tunnels للمحاكيات

وهذه من أقوى الميزات — Dev Tunnels تسمح للمحاكيات والأجهزة الفعلية بالوصول إلى APIs على localhost أثناء التطوير. لو جربت هذا من قبل تعرف كم كان الموضوع متعب:

var builder = DistributedApplication.CreateBuilder(args);

var productsApi = builder.AddProject<Projects.ProductsAPI>("productsapi")
    .WithExternalHttpEndpoints();

var mauiApp = builder.AddProject<Projects.MyMauiApp>("mauiapp")
    .WithReference(productsApi);

builder.Build().Run();

NativeAOT والتقليص (Trimming)

من التحسينات اللي أنا شخصياً كنت أنتظرها: دعم NativeAOT (الترجمة المسبقة للكود الأصلي). الفكرة إنه يحوّل كود .NET إلى كود أصلي قبل النشر، فتحصل على تطبيقات أصغر حجماً وأسرع في البدء.

الأرقام تتكلم

  • حجم أصغر: حتى 2.5 مرة أصغر في حجم الملف القابل للتنزيل
  • سرعة بدء: تحسن بمعدل 2x
  • أداء أفضل: تنفيذ أسرع للكود بشكل عام
  • ذاكرة أقل: بصمة ذاكرة أصغر في وقت التشغيل

كيفية التفعيل

أضف الخصائص التالية في ملف المشروع:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>net10.0-android;net10.0-ios</TargetFrameworks>
    <OutputType>Exe</OutputType>
    <RootNamespace>MyMauiApp</RootNamespace>
    <UseMaui>true</UseMaui>

    <!-- Enable NativeAOT for Release builds -->
    <PublishAot>true</PublishAot>

    <!-- Enable trimming for smaller size -->
    <PublishTrimmed>true</PublishTrimmed>
    <TrimMode>full</TrimMode>
  </PropertyGroup>
</Project>

التعامل مع التقليص

هنا لازم تكون حذر. عند تفعيل التقليص، قد يُزال كود يبدو غير مستخدم لكنه يُستدعى عبر Reflection. الحل؟ استخدم Attributes المناسبة:

using System.Diagnostics.CodeAnalysis;

public class MyViewModel
{
    [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
    public string Name { get; set; }

    [RequiresUnreferencedCode("Uses reflection to load plugins")]
    public void LoadPlugins()
    {
        // Reflection code here
    }
}

إعدادات التقليص المخصصة

تقدر تتحكم بالضبط في ما يتم الاحتفاظ به عبر ملف تكوين XML:

<!-- TrimmerRoots.xml -->
<linker>
  <assembly fullname="MyMauiApp">
    <type fullname="MyMauiApp.ViewModels.*" preserve="all" />
    <type fullname="MyMauiApp.Models.*" preserve="all" />
  </assembly>

  <assembly fullname="CommunityToolkit.Mvvm">
    <type fullname="*" preserve="all" />
  </assembly>
</linker>

ثم أضفه في ملف المشروع:

<ItemGroup>
  <TrimmerRootDescriptor Include="TrimmerRoots.xml" />
</ItemGroup>

القيود اللي لازم تعرفها

قبل ما تتحمس كثير، خذ هذه النقاط بالاعتبار:

  • ما يعمل مع كل المكتبات — خاصة اللي تعتمد بشكل كبير على Reflection
  • يتطلب اختباراً شاملاً للتأكد من عمل كل الوظائف
  • وقت البناء أطول بشكل ملحوظ
  • بعض السيناريوهات الديناميكية قد لا تعمل

الترقية من .NET 9 إلى .NET 10

الخبر الجيد إن الترقية عملية مباشرة نسبياً. الخبر الأقل جودة إنها تتطلب بعض الخطوات الدقيقة. لكن لا تقلق، سأمشي معك خطوة بخطوة.

الخطوة 1: تحديث ملف المشروع

قبل الترقية (.NET 9):

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>net9.0-android;net9.0-ios;net9.0-maccatalyst</TargetFrameworks>
    <TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">
      $(TargetFrameworks);net9.0-windows10.0.19041.0
    </TargetFrameworks>
    <OutputType>Exe</OutputType>
    <RootNamespace>MyMauiApp</RootNamespace>
    <UseMaui>true</UseMaui>
    <SingleProject>true</SingleProject>
  </PropertyGroup>
</Project>

بعد الترقية (.NET 10):

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>net10.0-android;net10.0-ios;net10.0-maccatalyst</TargetFrameworks>
    <TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">
      $(TargetFrameworks);net10.0-windows10.0.19041.0
    </TargetFrameworks>
    <OutputType>Exe</OutputType>
    <RootNamespace>MyMauiApp</RootNamespace>
    <UseMaui>true</UseMaui>
    <SingleProject>true</SingleProject>

    <!-- Enable XAML Source Generation -->
    <MauiXamlInflator>SourceGen</MauiXamlInflator>

    <!-- Android specifics -->
    <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
  </PropertyGroup>
</Project>

الخطوة 2: تحديث حزم NuGet

حدّث جميع الحزم للإصدارات المتوافقة:

dotnet add package CommunityToolkit.Maui --version 10.0.0
dotnet add package CommunityToolkit.Mvvm --version 9.0.0
dotnet add package Microsoft.Maui.Controls --version 10.0.0
dotnet add package Microsoft.Maui.Controls.Compatibility --version 10.0.0

الخطوة 3: استبدال ListView بـ CollectionView

ابحث عن جميع استخدامات ListView واستبدلها. يمكنك استخدام Find and Replace كبداية:

// البحث عن
<ListView

// الاستبدال بـ
<CollectionView

لكن لا تكتفي بذلك! راجع كل ملف يدوياً وتأكد من:

  • تغيير ItemSelected إلى SelectionChanged
  • إضافة SelectionMode="Single" إذا كنت تستخدم التحديد
  • إزالة ViewCell والاحتفاظ بالمحتوى فقط
  • تحديث الـ Code-Behind لاستخدام SelectionChangedEventArgs

الخطوة 4: التعامل مع إزالة MessagingCenter

هذه نقطة مهمة — MessagingCenter أصبح internal في .NET 10. البديل الموصى به هو WeakReferenceMessenger من CommunityToolkit.Mvvm.

الكود القديم:

// Sender
MessagingCenter.Send(this, "ProductUpdated", product);

// Receiver
MessagingCenter.Subscribe<MainPage, Product>(this, "ProductUpdated",
    (sender, product) =>
    {
        RefreshProduct(product);
    });

الكود الجديد (وهو أنظف بكثير بصراحة):

using CommunityToolkit.Mvvm.Messaging;

// Define a message class
public class ProductUpdatedMessage
{
    public Product Product { get; set; }
}

// Sender
WeakReferenceMessenger.Default.Send(new ProductUpdatedMessage
{
    Product = product
});

// Receiver - implement IRecipient interface
public class MainViewModel : IRecipient<ProductUpdatedMessage>
{
    public MainViewModel()
    {
        WeakReferenceMessenger.Default.Register(this);
    }

    public void Receive(ProductUpdatedMessage message)
    {
        RefreshProduct(message.Product);
    }
}

الخطوة 5: اختبار شامل

بعد كل التغييرات، لا تتخطَّ هذه الخطوة:

  1. تأكد من أن المشروع يبني بدون أخطاء
  2. اختبر على جميع المنصات المستهدفة
  3. تحقق من أن جميع الصفحات تفتح بشكل صحيح
  4. اختبر جميع سيناريوهات التفاعل
  5. راقب الأداء والذاكرة
  6. اختبر في وضع Release مع NativeAOT إن أمكن

تحسينات الأداء

.NET MAUI 10 جاء بتحسينات أداء ملموسة عبر جميع المنصات. وهذا ما كان المطورون ينتظرونه فعلاً.

تحسينات استهلاك الذاكرة

تم العمل على عدة جبهات:

  • تقليل التسريبات: إصلاح مئات حالات تسريب الذاكرة في Handlers
  • تحسين ImageSource: استخدام أفضل للـ cache وتحرير الموارد
  • تحسين CollectionView: إعادة استخدام أفضل للـ cells
  • تقليل Allocations: تقليل إنشاء كائنات مؤقتة أثناء العرض

سرعة تحميل واجهة المستخدم

بفضل XAML Source Generation والتحسينات الأخرى:

  • فتح الصفحات أسرع بمعدل 2-3x
  • تحميل الصور أسرع بنسبة 40%
  • استجابة أسرع للمس واللمسات المتعددة

دعم Android API 35 و36

.NET MAUI 10 يدعم أحدث إصدارات Android مع تحسينات مخصصة:

  • دعم Predictive Back Gesture في Android 14+
  • تحسينات في Edge-to-Edge display
  • دعم أفضل للأجهزة القابلة للطي (foldable devices)
  • تحسينات في الإشعارات والصلاحيات
<PropertyGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">
  <SupportedOSPlatformVersion>21.0</SupportedOSPlatformVersion>
  <TargetPlatformVersion>36.0</TargetPlatformVersion>
  <AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
</PropertyGroup>

تحسينات الرسوميات

تحسينات واضحة في عرض الرسوميات والرسوم المتحركة:

  • استخدام أفضل لـ hardware acceleration
  • تقليل frame drops في الرسوم المتحركة
  • دعم أفضل للشاشات عالية معدل التحديث (90Hz, 120Hz)

نصائح عملية وأفضل الممارسات

بعد ما استعرضنا الميزات، خلّيني أشاركك مجموعة نصائح عملية مبنية على تجارب فعلية.

1. فعّل XAML Source Generation فوراً

لا تتردد. فعّلها في كل المشاريع الجديدة، وفي المشاريع القائمة بعد اختبار أولي:

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

الفوائد فورية والمخاطر قليلة جداً.

2. خطط لترحيل ListView مبكراً

لا تنتظر حتى تتوقف Microsoft عن دعم ListView. ابدأ الآن:

  • أنشئ قائمة بجميع استخدامات ListView في مشروعك
  • رتبها حسب الأولوية — الأبسط أولاً
  • رحّل واحدة في كل مرة واختبرها بشكل كامل
  • وثّق أي تحديات أو أنماط مكررة

3. اختبر توافق NativeAOT مبكراً

لو تنوي تستخدم NativeAOT، لا تأجل الاختبار لنهاية المشروع:

  • فعّله في فرع تجريبي مبكراً
  • اختبر جميع المكتبات اللي تستخدمها
  • وثّق أي مشاكل واحلها تدريجياً
  • قارن الأداء وحجم الملف

4. استخدم .NET Aspire للتكامل مع الخلفية

إذا عندك backend APIs خاصة بك، استفد من Aspire:

builder.Services.AddHttpClient("MyAPI", client =>
{
    client.BaseAddress = new Uri("https+http://myapi");
})
.AddStandardResilienceHandler()
.AddServiceDiscovery();

5. استخدم CommunityToolkit بشكل مكثف

CommunityToolkit.Maui وCommunityToolkit.Mvvm يوفران أدوات لا غنى عنها:

builder
    .UseMauiApp<App>()
    .UseMauiCommunityToolkit()
    .ConfigureFonts(fonts =>
    {
        fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
    });

6. راقب الأداء باستخدام Profilers

استخدم أدوات التحليل المدمجة:

  • .NET Object Allocation Tracking
  • CPU Usage profiler
  • Memory Usage profiler
  • Android Studio Profiler لتطبيقات Android
  • Instruments لتطبيقات iOS

7. اعتمد نمط MVVM بالشكل الصحيح

CommunityToolkit.Mvvm يعطيك كود نظيف وقابل للصيانة:

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;

public partial class ProductViewModel : ObservableObject
{
    [ObservableProperty]
    private string _name;

    [ObservableProperty]
    private decimal _price;

    [RelayCommand]
    private async Task SaveAsync()
    {
        await _productService.SaveAsync(new Product
        {
            Name = Name,
            Price = Price
        });
    }

    [RelayCommand(CanExecute = nameof(CanDelete))]
    private async Task DeleteAsync()
    {
        await _productService.DeleteAsync(_productId);
    }

    private bool CanDelete() => _productId > 0;
}

8. استخدم Dependency Injection مع Binding Contexts

تجنب تعيين BindingContext في XAML مباشرة، واستخدم DI بدلاً من ذلك:

// In MauiProgram.cs
builder.Services.AddTransient<ProductViewModel>();
builder.Services.AddTransient<ProductPage>();

// In ProductPage constructor
public ProductPage(ProductViewModel viewModel)
{
    InitializeComponent();
    BindingContext = viewModel;
}

9. استفد من Shell Navigation

Shell يوفر نظام تنقل قوي ومرن — وهو الطريقة الموصى بها للتنقل في MAUI:

<Shell xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:views="clr-namespace:MyApp.Views"
       x:Class="MyApp.AppShell">

    <TabBar>
        <ShellContent Title="Home"
                     Icon="home.png"
                     ContentTemplate="{DataTemplate views:HomePage}" />

        <ShellContent Title="Products"
                     Icon="products.png"
                     ContentTemplate="{DataTemplate views:ProductsPage}" />

        <ShellContent Title="Settings"
                     Icon="settings.png"
                     ContentTemplate="{DataTemplate views:SettingsPage}" />
    </TabBar>

</Shell>

10. اختبر على أجهزة فعلية

المحاكيات ممتازة للتطوير، لكن الاختبار النهائي لازم يكون على أجهزة فعلية:

  • اختبر على أجهزة منخفضة ومتوسطة وعالية المواصفات
  • اختبر على أحجام شاشات مختلفة
  • اختبر على إصدارات OS مختلفة
  • راقب استهلاك البطارية والحرارة

الخلاصة

.NET MAUI 10 يمثل نقطة نضج حقيقية. ليس لأنه يضيف ميزات براقة فحسب، بل لأنه يحل مشاكل فعلية كان يعاني منها المطورون. ميزة XAML Source Generation وحدها تبرر الترقية — فهي تحل واحدة من أكبر نقاط الألم من أيام Xamarin.Forms.

التحسينات في الأداء مع NativeAOT والتقليص تجعل تطبيقات .NET MAUI منافسة قوية للتطبيقات الأصلية. ودعم Android API 35 و36 يضمن توافق تطبيقاتك مع متطلبات Google Play.

التكامل مع .NET Aspire يفتح آفاقاً جديدة لبناء تطبيقات موزعة متكاملة، حيث يتفاعل التطبيق المحمول بسلاسة مع الـ microservices.

وبخصوص إهمال ListView — قد يبدو مزعجاً في البداية، لكنه القرار الصحيح. CollectionView أفضل في كل شيء.

كلمة أخيرة

إذا كنت تبدأ مشروعاً جديداً، .NET MAUI 10 هو الخيار الواضح. إصدار LTS، جودة عالية، أداء ممتاز. فعّل XAML Source Generation من اليوم الأول، استخدم CollectionView، واعتمد على CommunityToolkit.

وإذا عندك مشروع قائم على .NET 8 أو 9، خطط للترقية. الفوائد تستحق الجهد فعلاً — خاصة لو تعاني من مشاكل أداء. أنشئ فرع تجريبي، اتبع الخطوات اللي شرحناها، واختبر بشكل شامل.

المستقبل يبدو مشرقاً لـ .NET MAUI. ابدأ اليوم، جرّب الميزات الجديدة، وشاركنا تجربتك.

عن الكاتب Editorial Team

Our team of expert writers and editors.