Migrowanie niestandardowego modułu renderowania platformy Xamarin.Forms do programu obsługi programu MAUI platformy .NET
Na platformie Xamarin.Forms niestandardowe programy renderowania mogą służyć do dostosowywania wyglądu i zachowania kontrolki oraz tworzenia nowych kontrolek międzyplatformowych. Każdy niestandardowy moduł renderowania ma odwołanie do kontrolki międzyplatformowej i często polega na INotifyPropertyChanged
wysyłaniu powiadomień o zmianie właściwości. Zamiast używać niestandardowych programów renderujących, interfejs użytkownika aplikacji wieloplatformowej platformy .NET (.NET MAUI) wprowadza nową koncepcję nazywaną procedurą obsługi.
Programy obsługi oferują wiele ulepszeń wydajności w przypadku niestandardowych programów renderujących. W zestawie ViewRenderer
narzędzi Xamarin.Forms klasa tworzy element nadrzędny. Na przykład w systemie Android tworzony jest element, ViewGroup
który jest używany do zadań pozycjonowania pomocniczego. W programie .NET MAUI ViewHandler<TVirtualView,TPlatformView> klasa nie tworzy elementu nadrzędnego, co pomaga zmniejszyć rozmiar hierarchii wizualizacji i zwiększyć wydajność aplikacji. Programy obsługi oddzielają również kontrolki platformy od struktury. Kontrola platformy musi obsługiwać tylko potrzeby platformy. Jest to nie tylko bardziej wydajne, ale znacznie łatwiejsze do rozszerzenia lub zastąpienia, jeśli jest to wymagane. Programy obsługi są również odpowiednie do ponownego użycia przez inne struktury, takie jak Comet i Fabulous. Aby uzyskać więcej informacji na temat procedur obsługi, zobacz Programy obsługi.
W zestawie OnElementChanged
narzędzi Xamarin.Forms metoda w niestandardowym rendererze tworzy kontrolkę platformy, inicjuje wartości domyślne, subskrybuje zdarzenia i obsługuje element Xamarin.Forms, do którego został dołączony moduł renderujący (OldElement
) i element dołączony do elementuNewElement
(). Ponadto pojedyncza OnElementPropertyChanged
metoda definiuje operacje, które mają być wywoływane w przypadku zmiany właściwości w kontrolce międzyplatformowej. Program .NET MAUI upraszcza to podejście, dzięki czemu każda zmiana właściwości jest obsługiwana przez oddzielną metodę i dlatego kod umożliwiający utworzenie kontrolki platformy, wykonanie konfiguracji kontrolki i przeprowadzenie oczyszczania kontrolek jest oddzielone różnymi metodami.
Proces migracji niestandardowej kontrolki platformy Xamarin.Forms wspieranej przez niestandardowe programy renderujące na każdej platformie do niestandardowej kontrolki programu MAUI platformy .NET obsługiwanej przez program obsługi na każdej platformie jest następujący:
- Utwórz klasę dla kontrolki międzyplatformowej, która zapewnia publiczny interfejs API kontrolki. Aby uzyskać więcej informacji, zobacz Tworzenie kontrolki międzyplatformowej.
- Utwórz klasę
partial
obsługi. Aby uzyskać więcej informacji, zobacz Tworzenie procedury obsługi. - W klasie obsługi utwórz PropertyMapper słownik, który definiuje akcje do wykonania po wystąpieniu zmian właściwości międzyplatformowych. Aby uzyskać więcej informacji, zobacz Tworzenie mapowania właściwości.
- Utwórz
partial
klasy procedury obsługi dla każdej platformy, która tworzy widoki natywne, które implementują kontrolkę międzyplatformową. Aby uzyskać więcej informacji, zobacz Tworzenie kontrolek platformy. - Zarejestruj procedurę obsługi przy użyciu ConfigureMauiHandlers metod i AddHandler w klasie aplikacji
MauiProgram
. Aby uzyskać więcej informacji, zobacz Rejestrowanie programu obsługi.
Następnie można użyć wieloplatformowej kontroli. Aby uzyskać więcej informacji, zobacz Korzystanie z kontroli międzyplatformowej.
Alternatywnie można przekonwertować niestandardowe programy renderujące, które dostosowują kontrolki platformy Xamarin.Forms, tak aby modyfikowały programy obsługi programu .NET MAUI. Aby uzyskać więcej informacji, zobacz Dostosowywanie kontrolek za pomocą procedur obsługi.
Tworzenie wieloplatformowej kontrolki
Aby utworzyć kontrolkę międzyplatformową, należy utworzyć klasę pochodzącą z Viewklasy :
namespace MyMauiControl.Controls
{
public class CustomEntry : View
{
public static readonly BindableProperty TextProperty =
BindableProperty.Create(nameof(Text), typeof(string), typeof(CustomEntry), null);
public static readonly BindableProperty TextColorProperty =
BindableProperty.Create(nameof(TextColor), typeof(Color), typeof(CustomEntry), null);
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public Color TextColor
{
get { return (Color)GetValue(TextColorProperty); }
set { SetValue(TextColorProperty, value); }
}
}
}
Kontrolka powinna udostępnić publiczny interfejs API, do którego będzie uzyskiwany dostęp jego program obsługi i kontrolować użytkowników. Kontrolki międzyplatformowe powinny pochodzić z Viewelementu , który reprezentuje element wizualny używany do umieszczania układów i widoków na ekranie.
Tworzenie programu obsługi
Po utworzeniu wieloplatformowej kontrolki należy utworzyć klasę partial
dla programu obsługi:
#if IOS || MACCATALYST
using PlatformView = Microsoft.Maui.Platform.MauiTextField;
#elif ANDROID
using PlatformView = AndroidX.AppCompat.Widget.AppCompatEditText;
#elif WINDOWS
using PlatformView = Microsoft.UI.Xaml.Controls.TextBox;
#elif (NETSTANDARD || !PLATFORM) || (NET6_0_OR_GREATER && !IOS && !ANDROID)
using PlatformView = System.Object;
#endif
using MyMauiControl.Controls;
using Microsoft.Maui.Handlers;
namespace MyMauiControl.Handlers
{
public partial class CustomEntryHandler
{
}
}
Klasa obsługi jest klasą częściową, której implementacja zostanie ukończona na każdej platformie z dodatkową klasą częściową.
Instrukcje warunkowe using
definiują PlatformView
typ na każdej platformie. Ostateczna instrukcja warunkowa using
definiuje PlatformView
, że jest równa System.Object
. Jest to konieczne, PlatformView
aby można było użyć typu w programie obsługi do użycia na wszystkich platformach. Alternatywą byłoby zdefiniowanie PlatformView
właściwości raz na platformę przy użyciu kompilacji warunkowej.
Tworzenie mapowania właściwości
Każda procedura obsługi zwykle udostępnia maper właściwości, który definiuje akcje, które należy wykonać, gdy zmiana właściwości ma miejsce w kontrolce międzyplatformowej. Typ PropertyMapper to Dictionary
element, który mapuje właściwości kontrolki międzyplatformowej na skojarzone akcje.
Uwaga
Maper właściwości zastępuje metodę OnElementPropertyChanged
w niestandardowym rendererze platformy Xamarin.Forms.
PropertyMapper program jest zdefiniowany w klasie .NET MAUI ViewHandler<TVirtualView,TPlatformView> i wymaga podania dwóch argumentów ogólnych:
- Klasa dla wieloplatformowej kontrolki, która pochodzi z klasy View.
- Klasa programu obsługi.
Poniższy przykład kodu przedstawia klasę CustomEntryHandler
rozszerzoną o definicję PropertyMapper :
public partial class CustomEntryHandler
{
public static PropertyMapper<CustomEntry, CustomEntryHandler> PropertyMapper = new PropertyMapper<CustomEntry, CustomEntryHandler>(ViewHandler.ViewMapper)
{
[nameof(CustomEntry.Text)] = MapText,
[nameof(CustomEntry.TextColor)] = MapTextColor
};
public CustomEntryHandler() : base(PropertyMapper)
{
}
}
Jest PropertyMapper to, Dictionary
którego klucz jest wartością string
i której wartość jest ogólną Action
wartością . Obiekt string
reprezentuje nazwę właściwości kontrolki międzyplatformowej i Action
reprezentuje metodę static
, która wymaga obsługi i kontroli międzyplatformowej jako argumentów. Na przykład podpis MapText
metody to public static void MapText(CustomEntryHandler handler, CustomEntry view)
.
Każda procedura obsługi platformy musi zapewniać implementacje akcji, które manipulują interfejsami API widoku natywnego. Gwarantuje to, że po ustawieniu właściwości na kontrolce międzyplatformowej podstawowy widok macierzysty zostanie zaktualizowany zgodnie z potrzebami. Zaletą tego podejścia jest to, że umożliwia łatwe dostosowywanie kontrolek międzyplatformowych, ponieważ maper właściwości można modyfikować przez użytkowników kontroli międzyplatformowej bez podklasy. Aby uzyskać więcej informacji, zobacz Dostosowywanie kontrolek za pomocą procedur obsługi.
Tworzenie kontrolek platformy
Po utworzeniu maperów dla programu obsługi należy podać implementacje programu obsługi na wszystkich platformach. Można to osiągnąć, dodając implementacje procedury obsługi częściowej klasy w folderach podrzędnych folderu Platformy . Możesz też skonfigurować projekt tak, aby obsługiwał wielowersyjność nazw plików lub wielowersyjność opartą na folderach lub oba te elementy.
Wielowersyjność oparta na nazwie pliku jest konfigurowana przez dodanie następującego kodu XML do pliku projektu jako elementów podrzędnych węzła <Project>
:
<!-- Android -->
<ItemGroup Condition="$(TargetFramework.StartsWith('net8.0-android')) != true">
<Compile Remove="**\*.Android.cs" />
<None Include="**\*.Android.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
</ItemGroup>
<!-- iOS and Mac Catalyst -->
<ItemGroup Condition="$(TargetFramework.StartsWith('net8.0-ios')) != true AND $(TargetFramework.StartsWith('net8.0-maccatalyst')) != true">
<Compile Remove="**\*.MaciOS.cs" />
<None Include="**\*.MaciOS.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
</ItemGroup>
<!-- Windows -->
<ItemGroup Condition="$(TargetFramework.Contains('-windows')) != true ">
<Compile Remove="**\*.Windows.cs" />
<None Include="**\*.Windows.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
</ItemGroup>
Aby uzyskać więcej informacji na temat konfigurowania wielu elementów docelowych, zobacz Konfigurowanie wielowersyjność.
Każda klasa obsługi platformy powinna być klasą częściową i pochodzić z ViewHandler<TVirtualView,TPlatformView> klasy, która wymaga dwóch argumentów typu:
- Klasa dla wieloplatformowej kontrolki, która pochodzi z klasy View.
- Typ widoku natywnego, który implementuje kontrolę międzyplatformową na platformie. Powinno to być identyczne z typem
PlatformView
właściwości w procedurze obsługi.
Ważne
Klasa ViewHandler<TVirtualView,TPlatformView> udostępnia VirtualView
właściwości i PlatformView
. Właściwość służy do uzyskiwania VirtualView
dostępu do kontroli międzyplatformowej z poziomu programu obsługi. Właściwość służy do uzyskiwania PlatformView
dostępu do widoku natywnego na każdej platformie, która implementuje kontrolę międzyplatformową.
Każda implementacja programu obsługi platformy powinna zastąpić następujące metody:
- CreatePlatformView, który powinien utworzyć i zwrócić widok macierzysty, który implementuje kontrolkę międzyplatformową.
- ConnectHandler, który powinien wykonać dowolną konfigurację widoku natywnego, taką jak inicjowanie widoku natywnego i wykonywanie subskrypcji zdarzeń.
- DisconnectHandler, które powinno wykonać dowolne czyszczenie widoku natywnego, takie jak anulowanie subskrypcji zdarzeń i usuwanie obiektów. Ta metoda celowo nie jest wywoływana przez program .NET MAUI. Zamiast tego należy wywołać ją samodzielnie z odpowiedniej lokalizacji w cyklu życia aplikacji. Aby uzyskać więcej informacji, zobacz Oczyszczanie widoku natywnego.
- CreatePlatformView, który powinien utworzyć i zwrócić widok macierzysty, który implementuje kontrolkę międzyplatformową.
- ConnectHandler, który powinien wykonać dowolną konfigurację widoku natywnego, taką jak inicjowanie widoku natywnego i wykonywanie subskrypcji zdarzeń.
- DisconnectHandler, które powinno wykonać dowolne czyszczenie widoku natywnego, takie jak anulowanie subskrypcji zdarzeń i usuwanie obiektów. Ta metoda jest domyślnie wywoływana automatycznie przez program .NET MAUI, chociaż to zachowanie można zmienić. Aby uzyskać więcej informacji, zobacz Odłączanie programu obsługi sterowania.
Uwaga
Przesłonięcia CreatePlatformView, ConnectHandleri DisconnectHandler to zastąpienia OnElementChanged
metody w niestandardowym rendererze platformy Xamarin.Forms.
Każda procedura obsługi platformy powinna również implementować akcje zdefiniowane w słownikach mapowania. Ponadto każdy program obsługi platformy powinien również dostarczać kod, zgodnie z wymaganiami, aby zaimplementować funkcjonalność kontroli międzyplatformowej na platformie. Alternatywnie w przypadku bardziej złożonych kontrolek może to być udostępniane przez dodatkowy typ.
W poniższym przykładzie pokazano implementację CustomEntryHandler
w systemie Android:
#nullable enable
using AndroidX.AppCompat.Widget;
using Microsoft.Maui.Handlers;
using Microsoft.Maui.Platform;
using MyMauiControl.Controls;
namespace MyMauiControl.Handlers
{
public partial class CustomEntryHandler : ViewHandler<CustomEntry, AppCompatEditText>
{
protected override AppCompatEditText CreatePlatformView() => new AppCompatEditText(Context);
protected override void ConnectHandler(AppCompatEditText platformView)
{
base.ConnectHandler(platformView);
// Perform any control setup here
}
protected override void DisconnectHandler(AppCompatEditText platformView)
{
// Perform any native view cleanup here
platformView.Dispose();
base.DisconnectHandler(platformView);
}
public static void MapText(CustomEntryHandler handler, CustomEntry view)
{
handler.PlatformView.Text = view.Text;
handler.PlatformView?.SetSelection(handler.PlatformView?.Text?.Length ?? 0);
}
public static void MapTextColor(CustomEntryHandler handler, CustomEntry view)
{
handler.PlatformView?.SetTextColor(view.TextColor.ToPlatform());
}
}
}
CustomEntryHandler
pochodzi z ViewHandler<TVirtualView,TPlatformView> klasy, z argumentem ogólnym CustomEntry
określającym typ kontrolki międzyplatformowej i AppCompatEditText
argumentem określającym typ kontrolki natywnej.
Zastąpienie CreatePlatformView tworzy i zwraca AppCompatEditText
obiekt. Przesłonięcia ConnectHandler to lokalizacja do wykonania dowolnej wymaganej konfiguracji widoku natywnego. Przesłonięcia DisconnectHandler to lokalizacja do wykonania dowolnego czyszczenia widoku natywnego, dlatego wywołuje metodę Dispose
w wystąpieniu AppCompatEditText
.
Procedura obsługi implementuje również akcje zdefiniowane w słowniku mapowania właściwości. Każda akcja jest wykonywana w odpowiedzi na zmianę właściwości w kontrolce międzyplatformowej i jest static
metodą, która wymaga obsługi i wystąpień kontrolek międzyplatformowych jako argumentów. W każdym przypadku akcja wywołuje metody zdefiniowane w kontrolce natywnej.
Rejestrowanie programu obsługi
Kontrolka niestandardowa i jej program obsługi muszą być zarejestrowane w aplikacji, zanim będzie można jej używać. Powinno się to zdarzyć w CreateMauiApp
metodzie w MauiProgram
klasie w projekcie aplikacji, czyli międzyplatformowym punkcie wejścia aplikacji:
using Microsoft.Extensions.Logging;
using MyMauiControl.Controls;
using MyMauiControl.Handlers;
namespace MyMauiControl;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
})
.ConfigureMauiHandlers(handlers =>
{
handlers.AddHandler(typeof(CustomEntry), typeof(CustomEntryHandler));
});
#if DEBUG
builder.Logging.AddDebug();
#endif
return builder.Build();
}
}
Procedura obsługi jest zarejestrowana w metodzie ConfigureMauiHandlers i AddHandler . Pierwszym argumentem AddHandler metody jest typ sterowania międzyplatformowego, a drugi argument jest jego typem obsługi.
Uwaga
Takie podejście rejestracji pozwala uniknąć skanowania zestawów platformy Xamarin.Forms, co jest powolne i kosztowne.
Korzystanie z kontroli międzyplatformowej
Po zarejestrowaniu programu obsługi w aplikacji można następnie użyć wieloplatformowego sterowania:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:MyMauiControl.Controls"
x:Class="MyMauiControl.MainPage">
<Grid>
<controls:CustomEntry Text="Hello world"
TextColor="Blue" />
</Grid>
</ContentPage>
Czyszczenie widoku natywnego
Implementacja programu obsługi każdej platformy zastępuje implementację DisconnectHandler , która służy do przeprowadzania oczyszczania widoku natywnego, takiego jak anulowanie subskrypcji z zdarzeń i usuwanie obiektów. Jednak to zastąpienie nie jest celowo wywoływane przez program .NET MAUI. Zamiast tego należy wywołać ją samodzielnie z odpowiedniej lokalizacji w cyklu życia aplikacji. Może to oznaczać, że strona zawierająca kontrolkę jest odchyłana, co powoduje, że zdarzenie strony Unloaded
zostanie podniesione.
Program obsługi zdarzeń dla zdarzenia strony Unloaded
można zarejestrować w języku XAML:
<ContentPage ...
xmlns:controls="clr-namespace:MyMauiControl.Controls"
Unloaded="ContentPage_Unloaded">
<Grid>
<controls:CustomEntry x:Name="customEntry"
... />
</Grid>
</ContentPage>
Program obsługi zdarzeń dla Unloaded
zdarzenia może następnie wywołać metodę w jego Handler
wystąpieniuDisconnectHandler:
void ContentPage_Unloaded(object sender, EventArgs e)
{
customEntry.Handler?.DisconnectHandler();
}
Rozłączanie programu obsługi sterowania
Implementacja programu obsługi każdej platformy zastępuje implementację DisconnectHandler , która służy do przeprowadzania oczyszczania widoku natywnego, takiego jak anulowanie subskrypcji z zdarzeń i usuwanie obiektów. Domyślnie programy obsługi automatycznie odłączają się od kontrolek, gdy to możliwe, na przykład podczas przechodzenia do tyłu w aplikacji.
W niektórych scenariuszach możesz chcieć kontrolować, kiedy program obsługi rozłącza się z jego kontrolką, co można osiągnąć za pomocą dołączonej HandlerProperties.DisconnectPolicy
właściwości. Ta właściwość wymaga argumentu z wyliczeniem HandlerDisconnectPolicy definiującym następujące wartości:
Automatic
, który wskazuje, że program obsługi zostanie automatycznie odłączony. Jest to wartość domyślna dołączonejHandlerProperties.DisconnectPolicy
właściwości.Manual
, który wskazuje, że program obsługi będzie musiał zostać odłączony ręcznie przez wywołanie implementacji DisconnectHandler() .
W poniższym przykładzie pokazano ustawienie dołączonej HandlerProperties.DisconnectPolicy
właściwości:
<controls:CustomEntry x:Name="customEntry"
Text="Hello world"
TextColor="Blue"
HandlerProperties.DisconnectPolicy="Manual" />
Podczas ustawiania dołączonej HandlerProperties.DisconnectPolicy
właściwości Manual
należy wywołać implementację programu obsługi DisconnectHandler samodzielnie z odpowiedniej lokalizacji w cyklu życia aplikacji. Można to osiągnąć, wywołując customEntry.Handler?.DisconnectHandler();
.
Ponadto istnieje DisconnectHandlers metoda rozszerzenia, która rozłącza programy obsługi z danego IViewelementu :
video.DisconnectHandlers();
Podczas odłączania DisconnectHandlers metoda będzie propagowana w dół drzewa kontrolek do momentu zakończenia lub odebrania kontrolki, która ustawiła zasady ręczne.