Sdílet prostřednictvím


Přizpůsobení ovládacích prvků pomocí obslužných rutin

Projděte si ukázku. Procházení ukázky

Obslužné rutiny lze přizpůsobit tak, aby zlepšily vzhled a chování ovládacího prvku napříč různými platformami nad rámec možností přizpůsobení dostupných prostřednictvím API ovládacího prvku. Toto přizpůsobení, které upravuje nativní zobrazení pro řízení napříč platformami, se dosahuje úpravou mapperu pro obslužnou rutinu pomocí jedné z následujících metod:

  • PrependToMapping, který upraví mapovač pro zpracovatele před aplikováním mapování ovládacích prvků .NET MAUI.
  • ModifyMapping, který upraví existující mapování.
  • AppendToMapping, který upravuje mapovač pro obslužnou rutinu poté, co bylo použito mapování ovládacích prvků .NET MAUI.

Každá z těchto metod má identický podpis, který vyžaduje dva argumenty:

  • Klíč založený na string. Při úpravě jednoho z mapování poskytovaných rozhraním .NET MAUI je nutné zadat klíč používaný rozhraním .NET MAUI. Hodnoty klíčů používané mapováním ovládacích prvků .NET MAUI jsou založené na názvech rozhraní a vlastností, například nameof(IEntry.IsPassword). Rozhraní, která abstrahují jednotlivé multiplatformní ovládací prvky, najdete v úložišti dotnet/maui. Jedná se o formát klíče, který byste měli použít, pokud chcete, aby se přizpůsobení obslužné rutiny spustilo při každé změně vlastnosti. Jinak může být klíč libovolnou hodnotou, která nemusí odpovídat názvu vlastnosti vystavené typem. Například lze MyCustomization zadat jako klíč, přičemž jakákoli modifikace nativního zobrazení je provedena jako přizpůsobení. Následkem tohoto formátu klíče je však to, že přizpůsobení obslužné rutiny se spustí pouze při první úpravě mapovače obslužné rutiny.
  • Funkce Action, která představuje metodu pro provedení přizpůsobení obslužné rutiny. Určuje Action dva argumenty:
    • Argument handler poskytuje instanci obslužné rutiny, která je přizpůsobována.
    • Argument view , který poskytuje instanci multiplatformního ovládacího prvku, který obslužná rutina implementuje.

Důležité

Přizpůsobení obslužné rutiny jsou globální a nejsou vymezeny na konkrétní instanci ovládacího prvku. Přizpůsobení obslužné rutiny může probíhat kdekoli ve vaší aplikaci. Jakmile je obslužná rutina přizpůsobená, ovlivní všechny ovládací prvky tohoto typu všude ve vaší aplikaci.

Každá třída obslužné rutiny zveřejňuje nativní zobrazení pro řízení napříč platformami prostřednictvím své PlatformView vlastnosti. Tato vlastnost je přístupná k nastavení nativních vlastností zobrazení, vyvolání nativních metod zobrazení a přihlášení k odběru událostí nativního zobrazení. Kromě toho je multiplatformní ovládací prvek implementovaný obslužnou rutinou zpřístupněn prostřednictvím jeho vlastnosti VirtualView.

Obslužné rutiny lze přizpůsobit pro jednotlivé platformy pomocí podmíněné kompilace, která umožňuje cílit kód na více platforem. Případně můžete pomocí částečných tříd uspořádat kód do složek a souborů specifických pro platformu. Další informace o podmíněné kompilaci naleznete v tématu Podmíněné kompilace.

Přizpůsobení ovládacího prvku

Zobrazení .NET MAUI Entry je jednořádkový ovládací prvek pro zadávání textu, který implementuje rozhraní IEntry. EntryHandler mapuje zobrazení Entry na následující nativní zobrazení pro každou platformu:

  • iOS/Mac Catalyst: UITextField
  • Android: AppCompatEditText
  • Windows: TextBox
  • iOS/Mac Catalyst: UITextField
  • Android: MauiAppCompatEditText
  • Windows: TextBox

Diagramy níže ukazují, jak je zobrazení Entry namapováno na své nativní zobrazení prostřednictvím EntryHandler.

Architektura zpracovatele vstupu

Architektura obsluhy vstupů

Mapovač Entry vlastností ve EntryHandler třídě mapuje vlastnosti ovládacího prvku napříč platformami na nativní rozhraní API pro zobrazení. Tím se zajistí, že když je vlastnost nastavena na Entry, základní nativní zobrazení se aktualizuje, je-li to nutné.

Mapovač vlastností lze upravit tak, aby se přizpůsobil Entry na jednotlivých platformách:

namespace CustomizeHandlersDemo.Views;

public partial class CustomizeEntryPage : ContentPage
{
    public CustomizeEntryPage()
    {
        InitializeComponent();
        ModifyEntry();
    }

    void ModifyEntry()
    {
        Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("MyCustomization", (handler, view) =>
        {
#if ANDROID
            handler.PlatformView.SetSelectAllOnFocus(true);
#elif IOS || MACCATALYST
            handler.PlatformView.EditingDidBegin += (s, e) =>
            {
                handler.PlatformView.PerformSelector(new ObjCRuntime.Selector("selectAll"), null, 0.0f);
            };
#elif WINDOWS
            handler.PlatformView.GotFocus += (s, e) =>
            {
                handler.PlatformView.SelectAll();
            };
#endif
        });
    }
}

V tomto příkladu se přizpůsobení prostřednictvím Entry provádí ve třídě stránky. Proto se všechny Entry ovládací prvky na Androidu, iOSu a Windows přizpůsobí po vytvoření instance CustomizeEntryPage . Vlastní nastavení se provádí přístupem k vlastnosti obslužné rutiny PlatformView, která poskytuje přístup k nativnímu zobrazení, které se mapuje na kontrolu mezi platformami na jednotlivých platformách. Nativní kód pak přizpůsobí obslužnou rutinu tak, že vybere veškerý text v Entry, jakmile získá fokus.

Další informace o mapovačích naleznete v tématu Mappers.

Přizpůsobení konkrétní instance ovládacího prvku

Obslužné rutiny jsou globální a přizpůsobení obslužné rutiny ovládacího prvku způsobí přizpůsobení všech ovládacích prvků stejného typu v aplikaci. Obslužné rutiny pro konkrétní instance ovládacího prvku je však možné přizpůsobit podtřídou ovládacího prvku a potom úpravou obslužné rutiny pro základní typ ovládacího prvku pouze v případě, že je ovládací prvek typu podtřídy. Pokud chcete například přizpůsobit konkrétní Entry ovládací prvek na stránce, která obsahuje více Entry ovládacích prvků, měli byste nejprve podtřídu Entry ovládacího prvku:

namespace CustomizeHandlersDemo.Controls
{
    internal class MyEntry : Entry
    {
    }
}

Potom můžete upravit EntryHandlervlastnost pomocí mapovače vlastností a provést požadovanou úpravu pouze instancím MyEntry :

Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("MyCustomization", (handler, view) =>
{
    if (view is MyEntry)
    {
#if ANDROID
        handler.PlatformView.SetSelectAllOnFocus(true);
#elif IOS || MACCATALYST
        handler.PlatformView.EditingDidBegin += (s, e) =>
        {
            handler.PlatformView.PerformSelector(new ObjCRuntime.Selector("selectAll"), null, 0.0f);
        };
#elif WINDOWS
        handler.PlatformView.GotFocus += (s, e) =>
        {
            handler.PlatformView.SelectAll();
        };
#endif
    }
});

Pokud se přizpůsobení obslužné rutiny provádí ve vaší App třídě, MyEntry všechny instance v aplikaci se přizpůsobí podle úprav obslužné rutiny.

Přizpůsobení ovládacího prvku pomocí životního cyklu obsluhy

Všechny prvky .NET MAUI založené na handlerech podporují události HandlerChanging a HandlerChanged. Událost HandlerChanged je vyvolána v případě, že nativní zobrazení, které implementuje multiplatformní řízení, je k dispozici a inicializováno. Událost HandlerChanging se vyvolá, když obslužný proces ovládacího prvku je připraven k odebrání z víceplatformního ovládání. Další informace o událostech životního cyklu obslužné rutiny naleznete v tématu Životní cyklus obslužné rutiny.

Životní cyklus obslužné rutiny lze použít k přizpůsobení obslužné rutiny. Například pokud se chcete přihlásit k odběru událostí nativního zobrazení nebo se odhlásit, musíte zaregistrovat obslužné rutiny pro události HandlerChanged a HandlerChanging na přizpůsobeném ovládacím prvku pro různé platformy.

<Entry HandlerChanged="OnEntryHandlerChanged"
       HandlerChanging="OnEntryHandlerChanging" />

Obslužné rutiny lze přizpůsobit na platformu pomocí podmíněné kompilace nebo pomocí částečných tříd pro uspořádání kódu do složek a souborů specifických pro platformu. Každý přístup bude postupně probírán, přizpůsobením objektu Entry tak, aby byl jeho veškerý text vybrán, když získá fokus.

Podmíněná kompilace

Soubor kódu obsahující obslužné rutiny pro události HandlerChanged a HandlerChanging je ukázán v následujícím příkladu, který používá podmíněnou kompilaci.

#if ANDROID
using AndroidX.AppCompat.Widget;
#elif IOS || MACCATALYST
using UIKit;
#elif WINDOWS
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml;
#endif

namespace CustomizeHandlersDemo.Views;

public partial class CustomizeEntryHandlerLifecyclePage : ContentPage
{
    public CustomizeEntryHandlerLifecyclePage()
    {
        InitializeComponent();
    }

    void OnEntryHandlerChanged(object sender, EventArgs e)
    {
        Entry entry = sender as Entry;
#if ANDROID
        (entry.Handler.PlatformView as AppCompatEditText).SetSelectAllOnFocus(true);
#elif IOS || MACCATALYST
        (entry.Handler.PlatformView as UITextField).EditingDidBegin += OnEditingDidBegin;
#elif WINDOWS
        (entry.Handler.PlatformView as TextBox).GotFocus += OnGotFocus;
#endif
    }

    void OnEntryHandlerChanging(object sender, HandlerChangingEventArgs e)
    {
        if (e.OldHandler != null)
        {
#if IOS || MACCATALYST
            (e.OldHandler.PlatformView as UITextField).EditingDidBegin -= OnEditingDidBegin;
#elif WINDOWS
            (e.OldHandler.PlatformView as TextBox).GotFocus -= OnGotFocus;
#endif
        }
    }

#if IOS || MACCATALYST
    void OnEditingDidBegin(object sender, EventArgs e)
    {
        var nativeView = sender as UITextField;
        nativeView.PerformSelector(new ObjCRuntime.Selector("selectAll"), null, 0.0f);
    }
#elif WINDOWS
    void OnGotFocus(object sender, RoutedEventArgs e)
    {
        var nativeView = sender as TextBox;
        nativeView.SelectAll();
    }
#endif
}
#if ANDROID
using Microsoft.Maui.Platform;
#elif IOS || MACCATALYST
using UIKit;
#elif WINDOWS
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml;
#endif

namespace CustomizeHandlersDemo.Views;

public partial class CustomizeEntryHandlerLifecyclePage : ContentPage
{
    public CustomizeEntryHandlerLifecyclePage()
    {
        InitializeComponent();
    }

    void OnEntryHandlerChanged(object sender, EventArgs e)
    {
        Entry entry = sender as Entry;
#if ANDROID
        (entry.Handler.PlatformView as MauiAppCompatEditText).SetSelectAllOnFocus(true);
#elif IOS || MACCATALYST
        (entry.Handler.PlatformView as UITextField).EditingDidBegin += OnEditingDidBegin;
#elif WINDOWS
        (entry.Handler.PlatformView as TextBox).GotFocus += OnGotFocus;
#endif
    }

    void OnEntryHandlerChanging(object sender, HandlerChangingEventArgs e)
    {
        if (e.OldHandler != null)
        {
#if IOS || MACCATALYST
            (e.OldHandler.PlatformView as UITextField).EditingDidBegin -= OnEditingDidBegin;
#elif WINDOWS
            (e.OldHandler.PlatformView as TextBox).GotFocus -= OnGotFocus;
#endif
        }
    }

#if IOS || MACCATALYST
    void OnEditingDidBegin(object sender, EventArgs e)
    {
        var nativeView = sender as UITextField;
        nativeView.PerformSelector(new ObjCRuntime.Selector("selectAll"), null, 0.0f);
    }
#elif WINDOWS
    void OnGotFocus(object sender, RoutedEventArgs e)
    {
        var nativeView = sender as TextBox;
        nativeView.SelectAll();
    }
#endif
}

Událost HandlerChanged je vyvolána po vytvoření a inicializaci nativního zobrazení, které implementuje multiplatformní ovládací prvek. Proto je obslužná rutina události tam, kde se mají provádět odběry nativních událostí. To vyžaduje přetypování PlatformView vlastnosti obslužné rutiny na typ nebo základní typ nativního zobrazení, aby bylo možné získat přístup k nativním událostem. V tomto příkladu se na iOS, Mac Catalyst a Windows událost přihlásí k odběru nativních událostí zobrazení, které se aktivují, když nativní zobrazení implementující Entry získají fokus OnEntryHandlerChanged.

Obslužné rutiny událostí OnEditingDidBegin a OnGotFocus přistupují k nativnímu zobrazení Entry na jejich příslušných platformách a vyberou veškerý text, který je v Entry.

Událost HandlerChanging se vyvolá před odebráním existující obslužné rutiny z ovládacího prvku pro různé platformy a před vytvořením nové obslužné rutiny pro řízení napříč platformami. Proto je obslužná rutina události tam, kde se mají odebrat odběry nativních událostí a provést další vyčištění. Objekt HandlerChangingEventArgs , který doprovází tuto událost, má OldHandler a NewHandler vlastnosti, které budou nastaveny na staré a nové obslužné rutiny v uvedeném pořadí. V tomto příkladu OnEntryHandlerChanging událost zruší odběr nativních událostí zobrazení na systémech iOS, Mac Catalyst a Windows.

Částečné třídy

Místo podmíněné kompilace je také možné použít částečné třídy k uspořádání kódu pro přizpůsobení ovládacích prvků do složek a souborů specifických pro platformu. Pomocí tohoto přístupu je kód přizpůsobení rozdělený do částečné třídy pro různé platformy a částečné třídy specifické pro platformu:

  • Částečná třída napříč platformami obvykle definuje členy, ale neimplementuje je a je vytvořená pro všechny platformy. Tato třída by neměla být umístěna do žádné podřízené složky platformy projektu, protože by to udělalo třídu specifickou pro platformu.
  • Částečná třída specifická pro platformu obvykle implementuje členy definované v částečné třídě pro různé platformy a je vytvořená pro jednu platformu. Tato třída by měla být umístěna do podřízené složky platformy pro vaši zvolenou platformu.

Následující příklad ukazuje částečnou třídu napříč platformami:

namespace CustomizeHandlersDemo.Views;

public partial class CustomizeEntryPartialMethodsPage : ContentPage
{
    public CustomizeEntryPartialMethodsPage()
    {
        InitializeComponent();
    }

    partial void ChangedHandler(object sender, EventArgs e);
    partial void ChangingHandler(object sender, HandlerChangingEventArgs e);

    void OnEntryHandlerChanged(object sender, EventArgs e) => ChangedHandler(sender, e);
    void OnEntryHandlerChanging(object sender, HandlerChangingEventArgs e) => ChangingHandler(sender, e);
}

V tomto příkladu dva obslužné rutiny událostí volají částečné metody pojmenované ChangedHandler a ChangingHandler, jejichž podpisy jsou definovány v částečné třídě pro různé platformy. Implementace částečné metody jsou pak definovány v částečných třídách specifických pro platformu, které by měly být umístěny ve správných podřízených složkách Platformy , aby se zajistilo, že se systém sestavení pokusí při sestavování pro konkrétní platformu pouze sestavit nativní kód. Například následující kód ukazuje CustomizeEntryPartialMethodsPage třídu ve složce Platforms>Windows projektu:

using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;

namespace CustomizeHandlersDemo.Views
{
    public partial class CustomizeEntryPartialMethodsPage : ContentPage
    {
        partial void ChangedHandler(object sender, EventArgs e)
        {
            Entry entry = sender as Entry;
            (entry.Handler.PlatformView as TextBox).GotFocus += OnGotFocus;
        }

        partial void ChangingHandler(object sender, HandlerChangingEventArgs e)
        {
            if (e.OldHandler != null)
            {
                (e.OldHandler.PlatformView as TextBox).GotFocus -= OnGotFocus;
            }
        }

        void OnGotFocus(object sender, RoutedEventArgs e)
        {
            var nativeView = sender as TextBox;
            nativeView.SelectAll();
        }
    }
}

Výhodou tohoto přístupu je, že podmíněná kompilace není nutná a že částečné metody nemusí být implementovány na každé platformě. Pokud na platformě není k dispozici implementace, metoda a všechna volání metody se odeberou v době kompilace. Informace o částečných metodách naleznete v části Částečné metody.

Informace o organizaci složky Platformy v projektu .NET MAUI najdete v části Částečné třídy a metody. Informace o tom, jak nakonfigurovat cílení na více platforem, abyste nemuseli umístit kód platformy do podsložek složky Platformy, najdete v tématu Konfigurace cílení na víceplatforem.