Zwiększanie Xamarin.Forms wydajności aplikacji
Rozwijanie 2016: Optymalizowanie wydajności aplikacji za pomocą polecenia Xamarin.Forms
Niska wydajność aplikacji przedstawia się na wiele sposobów. Może to sprawić, że aplikacja wydaje się nie odpowiadać, może powodować powolne przewijanie i może zmniejszyć żywotność baterii urządzenia. Jednak optymalizacja wydajności wymaga więcej niż tylko zaimplementowania wydajnego kodu. Należy również rozważyć środowisko użytkownika dotyczące wydajności aplikacji. Na przykład zapewnienie, że operacje są wykonywane bez blokowania użytkownikowi wykonywania innych działań, mogą pomóc w ulepszaniu środowiska użytkownika.
Istnieje wiele technik zwiększania wydajności i postrzeganej Xamarin.Forms wydajności aplikacji. Łącznie te techniki mogą znacznie zmniejszyć ilość pracy wykonywanej przez procesor CPU i ilość pamięci zużywanej przez aplikację.
Uwaga
Przed przeczytaniem tego artykułu należy najpierw przeczytać artykuł Wydajność międzyplatformowa, w którym omówiono techniki specyficzne dla platformy, aby poprawić użycie pamięci i wydajność aplikacji utworzonych przy użyciu platformy Xamarin.
Włączanie kompilatora XAML
Język XAML można opcjonalnie skompilować bezpośrednio w języku pośrednim (IL) za pomocą kompilatora XAML (XAMLC). XAMLC oferuje szereg korzyści:
- Wykonuje sprawdzanie czasu kompilacji kodu XAML, powiadamiając użytkownika o wszelkich błędach.
- Usuwa część czasu ładowania i tworzenia wystąpień dla elementów XAML.
- Pomaga to zmniejszyć rozmiar pliku końcowego zestawu, nie dołączając już plików xaml.
Funkcja XAMLC jest domyślnie włączona w nowych Xamarin.Forms rozwiązaniach. Jednak może być konieczne włączenie go w starszych rozwiązaniach. Aby uzyskać więcej informacji, zobacz Kompilowanie kodu XAML.
Używanie skompilowanych powiązań
Skompilowane powiązania zwiększają wydajność powiązań danych w Xamarin.Forms aplikacjach przez rozpoznawanie wyrażeń powiązań w czasie kompilacji, a nie w czasie wykonywania z odbiciem. Kompilowanie wyrażenia powiązania generuje skompilowany kod, który zazwyczaj rozwiązuje powiązanie 8–20 razy szybciej niż użycie powiązania klasycznego. Aby uzyskać więcej informacji, zobacz Skompilowane powiązania.
Zmniejszanie niepotrzebnych powiązań
Nie używaj powiązań dla zawartości, które można łatwo ustawić statycznie. Nie ma żadnych zalet związanych z danymi powiązania, które nie muszą być powiązane, ponieważ powiązania nie są opłacalne. Na przykład ustawienie Button.Text = "Accept"
ma mniejsze obciążenie niż powiązanie Button.Text
z właściwością viewmodel string
o wartości "Akceptuj".
Używanie szybkich modułów renderujących
Szybkie programy renderujące zmniejszają koszty Xamarin.Forms inflacji i renderowania kontrolek w systemie Android przez spłaszczenie wynikowej natywnej hierarchii kontroli. Zwiększa to wydajność dzięki tworzeniu mniejszej liczby obiektów, co z kolei skutkuje mniej złożonym drzewem wizualnym i mniejszym użyciem pamięci.
Od Xamarin.Forms wersji 4.0 wszystkie aplikacje przeznaczone FormsAppCompatActivity
domyślnie używają szybkich programów renderujących. Aby uzyskać więcej informacji, zobacz Fast Renderers (Szybkie programy renderowania).
Włączanie śledzenia uruchamiania w systemie Android
Przed czasem (AOT) kompilacja w systemie Android minimalizuje obciążenie uruchamiania aplikacji Just in Time (JIT) i użycie pamięci, kosztem utworzenia znacznie większego pakietu APK. Alternatywą jest użycie śledzenia uruchamiania, które zapewnia kompromis między rozmiarem pakietu APK systemu Android a czasem uruchamiania, w porównaniu z konwencjonalną kompilacją AOT.
Zamiast kompilować jak najwięcej aplikacji, jak to możliwe do niezarządzanego kodu, śledzenie uruchamiania kompiluje tylko zestaw metod zarządzanych, które reprezentują najdroższe części uruchamiania aplikacji w pustej Xamarin.Forms aplikacji. Takie podejście powoduje zmniejszenie rozmiaru pakietu APK w porównaniu z konwencjonalną kompilacją AOT, jednocześnie zapewniając podobne ulepszenia uruchamiania.
Włączanie kompresji układu
Kompresja układu usuwa określone układy z drzewa wizualnego, próbując poprawić wydajność renderowania stron. Korzyść z wydajności zapewniana różni się w zależności od złożoności strony, używanej wersji systemu operacyjnego i urządzenia, na którym działa aplikacja. Jednak największe wzrosty wydajności będą widoczne na starszych urządzeniach. Aby uzyskać więcej informacji, zobacz Kompresja układu.
Wybieranie prawidłowego układu
Układ, który jest zdolny do wyświetlania wielu elementów podrzędnych, ale ma tylko jedno dziecko, jest marnotrawny. Na przykład poniższy przykład kodu przedstawia element StackLayout
z pojedynczym elementem podrzędnym:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DisplayImage.HomePage">
<StackLayout>
<Image Source="waterfront.jpg" />
</StackLayout>
</ContentPage>
Jest to marne i StackLayout
element powinien zostać usunięty, jak pokazano w poniższym przykładzie kodu:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DisplayImage.HomePage">
<Image Source="waterfront.jpg" />
</ContentPage>
Ponadto nie należy podejmować próby odtworzenia wyglądu określonego układu przy użyciu kombinacji innych układów, ponieważ powoduje to niepotrzebne obliczenia układu. Na przykład nie próbuj odtworzyć Grid
układu przy użyciu kombinacji StackLayout
wystąpień. Poniższy przykład kodu przedstawia przykład tego złego rozwiązania:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Details.HomePage"
Padding="0,20,0,0">
<StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Name:" />
<Entry Placeholder="Enter your name" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Age:" />
<Entry Placeholder="Enter your age" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Occupation:" />
<Entry Placeholder="Enter your occupation" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Address:" />
<Entry Placeholder="Enter your address" />
</StackLayout>
</StackLayout>
</ContentPage>
Jest to marnotrawne, ponieważ wykonywane są niepotrzebne obliczenia układu. Zamiast tego żądany układ można lepiej osiągnąć przy użyciu elementu Grid
, jak pokazano w poniższym przykładzie kodu:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Details.HomePage"
Padding="0,20,0,0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<Label Text="Name:" />
<Entry Grid.Column="1" Placeholder="Enter your name" />
<Label Grid.Row="1" Text="Age:" />
<Entry Grid.Row="1" Grid.Column="1" Placeholder="Enter your age" />
<Label Grid.Row="2" Text="Occupation:" />
<Entry Grid.Row="2" Grid.Column="1" Placeholder="Enter your occupation" />
<Label Grid.Row="3" Text="Address:" />
<Entry Grid.Row="3" Grid.Column="1" Placeholder="Enter your address" />
</Grid>
</ContentPage>
Optymalizowanie wydajności układu
Aby uzyskać najlepszą możliwą wydajność układu, postępuj zgodnie z następującymi wytycznymi:
- Zmniejsz głębokość hierarchii układu, określając
Margin
wartości właściwości, umożliwiając tworzenie układów z mniejszą liczbą widoków zawijania. Aby uzyskać więcej informacji, zobacz Marginesy i wypełnienie. - W przypadku korzystania z elementu
Grid
spróbuj upewnić się, że jak najwięcej wierszy i kolumn jest ustawionych naAuto
rozmiar. Każdy wiersz lub kolumna o automatycznym rozmiarze spowoduje, że aparat układu wykona dodatkowe obliczenia układu. Zamiast tego należy użyć wierszy i kolumn o stałym rozmiarze, jeśli to możliwe. Alternatywnie ustaw wiersze i kolumny, aby zajmować proporcjonalną ilość miejsca z wartością wyliczenia, pod warunkiem, że drzewo nadrzędne jest zgodne zGridUnitType.Star
tymi wytycznymi dotyczącymi układu. - Nie ustawiaj
VerticalOptions
właściwości iHorizontalOptions
układu, chyba że jest to wymagane. Wartości domyślneLayoutOptions.Fill
iLayoutOptions.FillAndExpand
umożliwiają najlepszą optymalizację układu. Zmiana tych właściwości ma koszt i zużywa pamięć, nawet podczas ustawiania ich na wartości domyślne. - Unikaj używania zawsze
RelativeLayout
, gdy jest to możliwe. Spowoduje to, że procesor cpu będzie musiał wykonać znacznie więcej pracy. - Jeśli jest to
AbsoluteLayout
możliwe, należy unikać używaniaAbsoluteLayout.AutoSize
właściwości . - W przypadku korzystania z elementu
StackLayout
upewnij się, że tylko jedno dziecko ma ustawioną wartośćLayoutOptions.Expands
. Ta właściwość gwarantuje, że określone dziecko zajmie największe miejsce, któreStackLayout
może dać, i marnuje wykonywanie tych obliczeń więcej niż raz. - Unikaj wywoływania dowolnej metody
Layout
klasy, ponieważ powodują one wykonywanie kosztownych obliczeń układu. Zamiast tego prawdopodobnie można uzyskać żądane zachowanie układu, ustawiającTranslationX
właściwości iTranslationY
. Alternatywnie podklasaLayout<View>
klasy w celu osiągnięcia żądanego zachowania układu. - Nie aktualizuj żadnych
Label
wystąpień częściej niż jest to wymagane, ponieważ zmiana rozmiaru etykiety może spowodować ponowne obliczenie całego układu ekranu. - Nie ustawiaj
Label.VerticalTextAlignment
właściwości, chyba że jest to wymagane. LineBreakMode
Ustaw wszystkieLabel
wystąpienia naNoWrap
zawsze, gdy jest to możliwe.
Używanie programowania asynchronicznego
Ogólną szybkość reakcji aplikacji można zwiększyć, a wąskie gardła wydajności są często unikane przy użyciu programowania asynchronicznego. Na platformie .NET wzorzec asynchroniczny oparty na zadaniach (TAP) jest zalecanym wzorcem projektowym dla operacji asynchronicznych. Jednak nieprawidłowe użycie interfejsu TAP może spowodować, że aplikacje nie będą możliwe. W związku z tym podczas korzystania z interfejsu TAP należy postępować zgodnie z poniższymi wytycznymi.
Podstawy
Zapoznaj się z cyklem życia zadania, który jest reprezentowany
TaskStatus
przez wyliczenie. Aby uzyskać więcej informacji, zobacz Znaczenie stanu zadania i zadania.Task.WhenAll
Użyj metody , aby asynchronicznie czekać na zakończenie wielu operacji asynchronicznych, a nie pojedynczoawait
serię operacji asynchronicznych. Aby uzyskać więcej informacji, zobacz Task.WhenAll.Task.WhenAny
Użyj metody , aby asynchronicznie poczekać na zakończenie jednej z wielu operacji asynchronicznych. Aby uzyskać więcej informacji, zobacz Task.WhenAny.Task.Delay
Użyj metody , aby utworzyćTask
obiekt, który zakończy się po upływie określonego czasu. Jest to przydatne w przypadku scenariuszy, takich jak sondowanie danych i opóźnianie obsługi danych wejściowych użytkownika dla wstępnie określonego czasu. Aby uzyskać więcej informacji, zobacz Task.Delay.Wykonaj intensywne operacje synchroniczne procesora CPU w puli wątków przy użyciu
Task.Run
metody . Ta metoda jest skrótem dlaTaskFactory.StartNew
metody z najbardziej optymalnymi argumentami ustawionymi. Aby uzyskać więcej informacji, zobacz Task.Run.Unikaj próby utworzenia konstruktorów asynchronicznych. Zamiast tego należy użyć zdarzeń cyklu życia lub oddzielnej logiki inicjowania, aby poprawnie
await
zainicjować. Aby uzyskać więcej informacji, zobacz Konstruktory asynchroniczne w blog.stephencleary.com.Użyj wzorca opóźnionego zadania, aby uniknąć oczekiwania na wykonanie operacji asynchronicznych podczas uruchamiania aplikacji. Aby uzyskać więcej informacji, zobacz AsyncLazy.
Utwórz otokę zadań dla istniejących operacji asynchronicznych, które nie używają interfejsu TAP, tworząc
TaskCompletionSource<T>
obiekty. Te obiekty uzyskują korzyści zTask
programowania i umożliwiają kontrolowanie okresu istnienia i ukończenia skojarzonego elementuTask
. Aby uzyskać więcej informacji, zobacz Charakter zadaniaCompletionSource.Task
Zwróć obiekt, zamiast zwracać oczekiwanyTask
obiekt, gdy nie ma potrzeby przetwarzania wyniku operacji asynchronicznej. Jest to bardziej wydajne z powodu mniejszego przełączania kontekstu.Użyj biblioteki przepływów danych biblioteki równoległej zadań (TPL) w scenariuszach, takich jak przetwarzanie danych, gdy staną się dostępne, lub gdy masz wiele operacji, które muszą komunikować się ze sobą asynchronicznie. Aby uzyskać więcej informacji, zobacz Przepływ danych (biblioteka równoległa zadań).
INTERFEJS UŻYTKOWNIKA
Wywołaj asynchroniczną wersję interfejsu API, jeśli jest dostępna. Spowoduje to odblokowanie wątku interfejsu użytkownika, co pomoże ulepszyć środowisko użytkownika w aplikacji.
Zaktualizuj elementy interfejsu użytkownika przy użyciu danych z operacji asynchronicznych w wątku interfejsu użytkownika, aby uniknąć zgłaszania wyjątków. Jednak aktualizacje
ListView.ItemsSource
właściwości będą automatycznie marshalowane do wątku interfejsu użytkownika. Aby uzyskać informacje na temat określania, czy kod jest uruchomiony w wątku interfejsu użytkownika, zobacz Xamarin.Essentials: MainThread.Ważne
Wszystkie właściwości kontrolki aktualizowane za pośrednictwem powiązania danych będą automatycznie marshalowane do wątku interfejsu użytkownika.
Obsługa błędów
- Dowiedz się więcej o asynchronicznej obsłudze wyjątków. Nieobsługiwane wyjątki zgłaszane przez kod uruchomiony asynchronicznie są propagowane z powrotem do wątku wywołującego, z wyjątkiem niektórych scenariuszy. Aby uzyskać więcej informacji, zobacz Obsługa wyjątków (biblioteka równoległa zadań).
- Unikaj tworzenia
async void
metod i zamiast tego twórzasync Task
metody. Umożliwiają one łatwiejsze obsługę błędów, komponowanie i możliwość testowania. Wyjątkiem od tych wytycznych są asynchroniczne programy obsługi zdarzeń, które muszą zwrócić wartośćvoid
. Aby uzyskać więcej informacji, zobacz Unikanie Async Void. - Nie mieszaj kodu blokującego i asynchronicznego przez wywołanie
Task.Wait
metod ,Task.Result
lubGetAwaiter().GetResult
, ponieważ mogą one spowodować zakleszczenie. Jeśli jednak te wytyczne muszą zostać naruszone, preferowaną metodą jest wywołanieGetAwaiter().GetResult
metody, ponieważ zachowuje wyjątki zadań. Aby uzyskać więcej informacji, zobacz Async All the Way and Task Exception Handling in .NET 4.5 (Asynchronizuj całą drogę i obsługę wyjątków zadań na platformie .NET 4.5). ConfigureAwait
Użyj metody , jeśli to możliwe, aby utworzyć kod wolny od kontekstu. Kod bez kontekstu ma lepszą wydajność dla aplikacji mobilnych i jest przydatną techniką unikania zakleszczenia podczas pracy z częściowo asynchroniczną bazą kodu. Aby uzyskać więcej informacji, zobacz Konfigurowanie kontekstu.- Użyj zadań kontynuacji dla funkcji, takich jak obsługa wyjątków zgłaszanych przez poprzednią operację asynchroniczną, i anulowanie kontynuacji przed jej uruchomieniem lub uruchomieniem. Aby uzyskać więcej informacji, zobacz Łączenie zadań za pomocą zadań ciągłych.
- Użyj implementacji asynchronicznej
ICommand
, gdy operacje asynchroniczne są wywoływane z klasyICommand
. Dzięki temu można obsłużyć wszelkie wyjątki w asynchronicznej logice poleceń. Aby uzyskać więcej informacji, zobacz Async Programming: Patterns for Asynchronous MVVM Applications: Commands (Asynchroniczne programowanie: wzorce dla asynchronicznych aplikacji MVVM: polecenia).
Starannie wybierz kontener wstrzykiwania zależności
Kontenery wstrzykiwania zależności wprowadzają dodatkowe ograniczenia wydajności do aplikacji mobilnych. Rejestrowanie i rozpoznawanie typów w kontenerze ma koszt wydajności ze względu na użycie odbicia kontenera do tworzenia każdego typu, zwłaszcza jeśli zależności są odtwarzane dla każdej nawigacji stron w aplikacji. Jeśli istnieje wiele lub głębokie zależności, koszt tworzenia może znacznie wzrosnąć. Ponadto rejestracja typu, która zwykle występuje podczas uruchamiania aplikacji, może mieć zauważalny wpływ na czas uruchamiania, zależny od używanego kontenera.
Alternatywnie iniekcja zależności może być bardziej wydajna, implementując ją ręcznie przy użyciu fabryk.
Tworzenie aplikacji powłoki
Xamarin.Forms Aplikacje powłoki zapewniają środowisko nawigacji z opiniami na podstawie wysuwanych i kart. Jeśli środowisko użytkownika aplikacji można zaimplementować za pomocą powłoki, warto to zrobić. Aplikacje powłoki pomagają uniknąć słabego środowiska uruchamiania, ponieważ strony są tworzone na żądanie w odpowiedzi na nawigację, a nie podczas uruchamiania aplikacji, co występuje w przypadku aplikacji korzystających z "TabbedPage". Aby uzyskać więcej informacji, zobacz Xamarin.Forms Powłoka.
Używanie kontrolki CollectionView zamiast kontrolki ListView
CollectionView
to widok do prezentowania list danych przy użyciu różnych specyfikacji układu. Zapewnia bardziej elastyczną i wydajną alternatywę dla ListView
elementu . Aby uzyskać więcej informacji, zobacz Xamarin.Forms CollectionView.
Optymalizowanie wydajności elementu ListView
W przypadku korzystania z programu ListView
istnieje wiele środowisk użytkownika, które należy zoptymalizować:
- Inicjowanie — interwał czasu rozpoczynający się od utworzenia kontrolki i kończący się, gdy elementy są wyświetlane na ekranie.
- Przewijanie — możliwość przewijania listy i upewnienia się, że interfejs użytkownika nie pozostaje w tyle za gestami dotykowymi.
- Interakcja z dodawaniem, usuwaniem i wybieraniem elementów.
Kontrolka ListView
wymaga, aby aplikacja dostarczała dane i szablony komórek. Sposób osiągnięcia tego celu będzie miał duży wpływ na wydajność kontrolki. Aby uzyskać więcej informacji, zobacz ListView Performance (Wydajność elementu ListView).
Optymalizowanie zasobów obrazu
Wyświetlanie zasobów obrazu może znacznie zwiększyć zużycie pamięci przez aplikację. W związku z tym należy je utworzyć tylko wtedy, gdy jest to wymagane i należy je zwolnić natychmiast, gdy aplikacja nie będzie już ich wymagała. Jeśli na przykład aplikacja wyświetla obraz, odczytując dane ze strumienia, upewnij się, że strumień jest tworzony tylko wtedy, gdy jest wymagany, i upewnij się, że strumień jest zwalniany, gdy nie jest już wymagany. Można to osiągnąć, tworząc strumień po utworzeniu strony lub gdy Page.Appearing
zdarzenie jest uruchamiane, a następnie dysponując strumień po Page.Disappearing
uruchomieniu zdarzenia.
Podczas pobierania obrazu do wyświetlania za ImageSource.FromUri
pomocą metody buforuj pobrany obraz, upewniając się, że UriImageSource.CachingEnabled
właściwość jest ustawiona na true
wartość . Aby uzyskać więcej informacji, zobacz Praca z obrazami.
Aby uzyskać więcej informacji, zobacz Optymalizowanie zasobów obrazów.
Zmniejszanie rozmiaru drzewa wizualnego
Zmniejszenie liczby elementów na stronie spowoduje szybsze renderowanie strony. Istnieją dwie główne techniki osiągnięcia tego celu. Pierwszym z nich jest ukrycie elementów, które nie są widoczne. Właściwość IsVisible
każdego elementu określa, czy element powinien być częścią drzewa wizualnego, czy nie. W związku z tym, jeśli element nie jest widoczny, ponieważ jest ukryty za innymi elementami, usuń element lub ustaw jego IsVisible
właściwość na false
.
Drugą techniką jest usunięcie niepotrzebnych elementów. Na przykład poniższy przykład kodu przedstawia układ strony zawierający wiele Label
obiektów:
<StackLayout>
<StackLayout Padding="20,20,0,0">
<Label Text="Hello" />
</StackLayout>
<StackLayout Padding="20,20,0,0">
<Label Text="Welcome to the App!" />
</StackLayout>
<StackLayout Padding="20,20,0,0">
<Label Text="Downloading Data..." />
</StackLayout>
</StackLayout>
Ten sam układ strony można zachować przy użyciu mniejszej liczby elementów, jak pokazano w poniższym przykładzie kodu:
<StackLayout Padding="20,35,20,20" Spacing="25">
<Label Text="Hello" />
<Label Text="Welcome to the App!" />
<Label Text="Downloading Data..." />
</StackLayout>
Zmniejsz rozmiar słownika zasobów aplikacji
Wszystkie zasoby używane w całej aplikacji powinny być przechowywane w słowniku zasobów aplikacji, aby uniknąć duplikowania. Pomoże to zmniejszyć ilość kodu XAML, który musi zostać przeanalizowany w całej aplikacji. Poniższy przykład kodu przedstawia HeadingLabelStyle
zasób, który jest używany dla całej aplikacji, a więc jest zdefiniowany w słowniku zasobów aplikacji:
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Resources.App">
<Application.Resources>
<ResourceDictionary>
<Style x:Key="HeadingLabelStyle" TargetType="Label">
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="FontSize" Value="Large" />
<Setter Property="TextColor" Value="Red" />
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>
Jednak kod XAML specyficzny dla strony nie powinien być uwzględniony w słowniku zasobów aplikacji, ponieważ zasoby będą następnie analizowane podczas uruchamiania aplikacji, a nie wtedy, gdy jest to wymagane przez stronę. Jeśli zasób jest używany przez stronę, która nie jest stroną uruchamiania, powinna zostać umieszczona w słowniku zasobów dla tej strony, co pomaga zmniejszyć liczbę kodu XAML analizowanego podczas uruchamiania aplikacji. Poniższy przykład kodu przedstawia HeadingLabelStyle
zasób, który znajduje się tylko na jednej stronie, a więc jest zdefiniowany w słowniku zasobów strony:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Test.HomePage"
Padding="0,20,0,0">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="HeadingLabelStyle" TargetType="Label">
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="FontSize" Value="Large" />
<Setter Property="TextColor" Value="Red" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>
Aby uzyskać więcej informacji na temat zasobów aplikacji, zobacz Style XAML.
Używanie niestandardowego wzorca modułu renderowania
Większość Xamarin.Forms klas rendererów uwidacznia metodę OnElementChanged
, która jest wywoływana podczas tworzenia niestandardowej Xamarin.Forms kontrolki w celu renderowania odpowiedniej kontrolki natywnej. Niestandardowe klasy modułu renderowania, w każdym projekcie platformy, a następnie przesłoń tę metodę, aby utworzyć wystąpienie i dostosować kontrolkę natywną. Metoda SetNativeControl
jest używana do tworzenia wystąpienia kontrolki natywnej, a ta metoda przypisze również odwołanie do kontrolki Control
do właściwości .
Jednak w niektórych okolicznościach metoda może być wywoływana OnElementChanged
wiele razy. W związku z tym, aby zapobiec wyciekom pamięci, które mogą mieć wpływ na wydajność, należy zachować ostrożność podczas tworzenia wystąpienia nowej natywnej kontrolki. Podejście do użycia podczas tworzenia wystąpienia nowej natywnej kontrolki w niestandardowym programie renderującym jest pokazane w poniższym przykładzie kodu:
protected override void OnElementChanged (ElementChangedEventArgs<NativeListView> e)
{
base.OnElementChanged (e);
if (e.OldElement != null)
{
// Unsubscribe from event handlers and cleanup any resources
}
if (e.NewElement != null)
{
if (Control == null)
{
// Instantiate the native control with the SetNativeControl method
}
// Configure the control and subscribe to event handlers
}
}
Nową kontrolkę natywną należy utworzyć tylko raz, gdy Control
właściwość ma wartość null
. Ponadto kontrolka powinna być tworzona, konfigurowana i subskrybowana tylko po dołączeniu niestandardowego modułu renderowania do nowego Xamarin.Forms elementu. Podobnie wszystkie programy obsługi zdarzeń, które zostały subskrybowane, powinny być anulowane tylko wtedy, gdy element renderujący jest dołączony do zmian. Wdrożenie tego podejścia pomoże stworzyć wydajny niestandardowy moduł renderujący, który nie cierpi na przecieki pamięci.
Ważne
Metoda SetNativeControl
powinna być wywoływana tylko wtedy, gdy e.NewElement
właściwość nie null
ma wartości , a Control
właściwość to null
.
Aby uzyskać więcej informacji na temat niestandardowych modułów renderujących, zobacz Dostosowywanie kontrolek na każdej platformie.