Megosztás a következőn keresztül:


Vezérlők testreszabása kezelőkkel

Minták böngészése. Minták böngészése

A kezelők testre szabhatók, hogy a platformokon átívelő vezérlők megjelenését és viselkedését az API által lehetséges testreszabáson túl is fokozzák. Ez a testreszabás, amely módosítja a platformfüggetlen vezérlőelem natív nézeteit, úgy érhető el, hogy módosítja egy kezelő leképezését az alábbi módszerek egyikével:

  • PrependToMapping, amely módosítja a kezelőhöz tartozó leképezőt, mielőtt a .NET MAUI vezérlők leképezése megtörténik.
  • ModifyMapping, amely módosítja a meglévő leképezést.
  • AppendToMapping, amely módosítja egy kezelő leképezését a .NET MAUI-vezérlőleképezések alkalmazása után.

Mindegyik metódus azonos aláírást használ, amely két argumentumot igényel:

  • Egy string-alapú kulcs. A .NET MAUI által biztosított leképezések egyikének módosításakor meg kell adni a .NET MAUI által használt kulcsot. A .NET MAUI vezérlőleképezések által használt fő értékek például nameof(IEntry.IsPassword)felület- és tulajdonságneveken alapulnak. A dotnet/maui adattárban megtalálhatja azokat a felületeket, amelyek minden platformfüggetlen vezérlőt elvonnak. Ezt a kulcsformátumot kell használni, ha azt szeretné, hogy a kezelő testreszabása minden alkalommal fusson, amikor egy tulajdonság megváltozik. Ellenkező esetben a kulcs tetszőleges érték lehet, amely nem felel meg egy típus által közzétett tulajdonság nevének. Megadható például MyCustomization kulcsként, és a testreszabás során bármilyen natív nézetmódosítást végrehajthat. Ennek a kulcsformátumnak azonban az a következménye, hogy a kezelő testreszabása csak a kezelő mapperjének első módosításakor lesz futtatva.
  • Az Action a módszer, amely végrehajtja a kezelő testreszabását. A Action két argumentumot adja meg:
    • Egy handler argumentum, amely a testre szabandó kezelő egy példányát adja meg.
    • Egy view argumentum, amely a kezelő által implementálható platformfüggetlen vezérlőelem egy példányát biztosítja.

Fontos

A kezelő testreszabásai globálisak, és nem tartoznak egy adott vezérlőpéldány hatókörébe. A kezelő testreszabása az alkalmazásban bárhol megtörténhet. Miután testre szabta a kezelőt, az az alkalmazás minden részén hatással van az ilyen típusú vezérlőkre.

Minden kezelőosztály a PlatformView tulajdonságán keresztül teszi elérhetővé a platformfüggetlen vezérlőelem natív nézetét. Ez a tulajdonság elérhető natív nézettulajdonságok beállításához, natív nézetmetszetek meghívásához és natív nézetesemények előfizetéséhez. Emellett a kezelő által implementált platformfüggetlen vezérlés a VirtualView tulajdonságán keresztül érhető el.

A kezelők platformonként testre szabhatók feltételes fordítás használatával, hogy több platformra célozzák a kódot. Másik lehetőségként részleges osztályokkal platformspecifikus mappákba és fájlokba rendezheti a kódot. A feltételes fordítással kapcsolatos további információkért lásd a feltételes fordítást.

Vezérlőelem testreszabása

A .NET MAUI Entry nézet egy egysoros szövegbeviteli vezérlő, amely implementálja a IEntry felületet. A EntryHandler leképezi a Entry nézetet az alábbi saját platformnézetekre:

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

Az alábbi diagramok azt mutatják be, hogy a Entry nézet hogyan van megfeleltetve a natív nézeteihez a EntryHandlerkövetkezőn keresztül:

Bejegyzéskezelő architektúra.

Bejegyzéskezelő architektúra.

Az Entry tulajdonság-leképezője, a EntryHandler osztályban, leképezi a platformfüggetlen vezérlő tulajdonságait a natív nézet API-hoz. Ez biztosítja, hogy amikor egy tulajdonság be van állítva a Entry elemre, a mögöttes natív nézet szükség szerint frissül.

A tulajdonság-leképező az egyes platformokon testre szabható Entry :

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
        });
    }
}

Ebben a példában a Entry testreszabás egy laposztályban történik. Ezért az Android, az iOS és a Windows összes Entry vezérlője testre lesz szabva a CustomizeEntryPage példány létrehozása után. A testreszabás a kezelők PlatformView tulajdonságának elérésével történik, amely hozzáférést biztosít az egyes platformok platformfüggetlen vezérlőjére leképező natív nézethez. A natív kód ezután testre szabja a kezelőt úgy, hogy kijelöli az összes szöveget a Entry fókuszba kerüléskor.

További információ a mapperekről: Mappers.

Adott vezérlőpéldány testreszabása

A kezelők globálisak, és ha egy vezérlőhöz testre szab egy kezelőt, az az alkalmazás minden azonos típusú vezérlőjének testreszabását eredményezi. Az egyes vezérlőpéldányok kezelői azonban testre szabhatók a vezérlő alosztályozásával, majd az alap vezérlőelemtípus kezelőjének módosításával, csak akkor, ha a vezérlő alosztályozott típusú. Ha például egy adott Entry vezérlőelemet szeretne testre szabni egy több Entry vezérlőt tartalmazó lapon, először a vezérlőelemet kell alásorolnia Entry :

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

Ezután testre szabhatja a EntryHandler tulajdonság-leképezőn keresztül, hogy a kívánt módosítást csak a MyEntry példányokra végezze el.

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
    }
});

Ha a kezelő testreszabása az ön App osztályában történik, az alkalmazás bármely MyEntry példánya igazodik a kezelő módosításához.

Vezérlő testreszabása a kezelő életciklusának használatával

Minden kezelőalapú .NET MAUI-vezérlő támogatja HandlerChanging és HandlerChanged eseményeket. Az HandlerChanged esemény akkor jön elő, ha a platformfüggetlen vezérlőt megvalósító natív nézet elérhető és inicializálható. Az HandlerChanging esemény akkor lép fel, amikor a vezérlő kezelője hamarosan el lesz távolítva a platformfüggetlen vezérlőből. A kezelő életciklus-eseményeiről további információt a Kezelő életciklusa című témakörben talál.

A kezelő életciklusa felhasználható a kezelő egyedi beállításainak végrehajtására. Ha például natív nézet eseményekre szeretne előfizetni és leiratkozni, regisztrálnia kell az eseménykezelőket a HandlerChanged és HandlerChanging eseményekhez a testre szabott platformfüggetlen vezérlőn.

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

A kezelők platformonként testre szabhatók feltételes fordítással, vagy részleges osztályok használatával a kód platformspecifikus mappákba és fájlokba való rendszerezéséhez. Minden megközelítést sorra tárgyalunk, egy Entry testreszabásával, úgy, hogy a fókuszba kerülésekor az összes szöveg ki legyen jelölve.

Feltételes kompilálás

A következő példa a kód mögötti fájlt mutatja, amely feltételes fordítást használ és tartalmazza az eseményekhez tartozó HandlerChanged és HandlerChanging eseménykezelőket.

#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
}

Az HandlerChanged esemény a platformfüggetlen vezérlőt megvalósító natív nézet létrehozása és inicializálása után jön létre. Ezért az eseménykezelőben natív esemény-előfizetéseket kell végrehajtani. Ehhez meg kell adni a PlatformView kezelő tulajdonságát a natív nézet típusának vagy alaptípusának, hogy a natív események elérhetők legyenek. Ebben a példában iOS, Mac Catalyst és Windows rendszeren az OnEntryHandlerChanged esemény feliratkozik a natív nézet eseményeire, amelyek akkor jelentkeznek, amikor a Entry-t megvalósító natív nézetek kapnak fókuszt.

A OnEditingDidBegin és OnGotFocus eseménykezelők hozzáférnek a natív nézethez a Entry saját platformjukon, és kiválasztják a Entry-ban található összes szöveget.

Az HandlerChanging eseményt a rendszer azelőtt hozza létre, hogy a meglévő kezelő el lesz távolítva a platformfüggetlen vezérlőből, és mielőtt létrejön a platformfüggetlen vezérlő új kezelője. Ezért az eseménykezelőben el kell távolítani a natív esemény-előfizetéseket, és más tisztítást kell végezni. Az HandlerChangingEventArgs objektum, amely kíséri ezt az eseményt, OldHandler és NewHandler tulajdonságokkal rendelkezik, amelyek a régi és az új kezelőkre lesznek beállítva. Ebben a példában az OnEntryHandlerChanging esemény eltávolítja az előfizetést a natív megtekintési eseményekre iOS, Mac Catalyst és Windows rendszeren.

Részleges osztályok

A feltételes fordítás helyett részleges osztályok használatával is rendszerezheti a vezérlő testreszabási kódját platformspecifikus mappákba és fájlokba. Ezzel a módszerrel a testreszabási kód egy platformfüggetlen részleges osztályra és egy platformspecifikus részleges osztályra van elválasztva:

  • A platformfüggetlen részleges osztály általában meghatározza a tagokat, de nem implementálja őket, és minden platformhoz készült. Ezt az osztályt nem szabad a projekt egyik Platform gyermekmappájába sem helyezni, mert ez platformspecifikus osztálysá tenné.
  • A platformspecifikus részleges osztály általában a platformfüggetlen részleges osztályban meghatározott tagokat implementálja, és egyetlen platformhoz készült. Ezt az osztályt a választott platform Platformok mappájának gyermekmappájába kell helyezni.

Az alábbi példa egy platformfüggetlen részleges osztályt mutat be:

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);
}

Ebben a példában a két eseménykezelő részleges metódusokat hív meg ChangedHandler , amelyek ChangingHandleraláírása a platformfüggetlen részleges osztályban van definiálva. A részleges metódus implementációit ezután a platformspecifikus részleges osztályok határozzák meg, amelyeket a megfelelő platformok gyermekmappáiba kell helyezni, hogy a buildelési rendszer csak natív kódot hozzon létre az adott platform létrehozásakor. A következő kód például a CustomizeEntryPartialMethodsPage projekt Platform Windows> mappájában lévő osztályt mutatja be:

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();
        }
    }
}

Ennek a megközelítésnek az az előnye, hogy nincs szükség feltételes fordításra, és hogy a részleges metódusokat nem kell implementálnunk az egyes platformokon. Ha egy implementáció nem érhető el egy platformon, akkor a metódus és a metódushoz intézett összes hívás fordításkor törlődik. A részleges metódusokról további információt a Részleges metódusok című témakörben talál.

A Platformok mappa .NET MAUI-projektben való szervezéséről további információt a Részleges osztályok és metódusok című témakörben talál. Ha tudni szeretné, hogyan konfigurálhat többhelyes célzást, hogy ne kelljen platformkódot helyeznie a Platformok mappa almappáiba, olvassa el a Többhelyes célzás konfigurálása című témakört.