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 Gridspróbuj upewnić się, że jak najwięcej wierszy i kolumn jest ustawionych na Auto 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 z GridUnitType.Star tymi wytycznymi dotyczącymi układu.
  • Nie ustawiaj VerticalOptions właściwości i HorizontalOptions układu, chyba że jest to wymagane. Wartości domyślne LayoutOptions.Fill i LayoutOptions.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 AbsoluteLayoutmożliwe, należy unikać używania AbsoluteLayout.AutoSize właściwości .
  • W przypadku korzystania z elementu StackLayoutupewnij się, że tylko jedno dziecko ma ustawioną wartość LayoutOptions.Expands. Ta właściwość gwarantuje, że określone dziecko zajmie największe miejsce, które StackLayout 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ąc TranslationX właściwości i TranslationY . Alternatywnie podklasa Layout<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 wszystkie Label wystąpienia na NoWrap 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 pojedynczo await 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 dla TaskFactory.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 z Task programowania i umożliwiają kontrolowanie okresu istnienia i ukończenia skojarzonego elementu Task. Aby uzyskać więcej informacji, zobacz Charakter zadaniaCompletionSource.

  • Task Zwróć obiekt, zamiast zwracać oczekiwany Task 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órz async 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.Waitmetod , Task.Resultlub GetAwaiter().GetResult , ponieważ mogą one spowodować zakleszczenie. Jeśli jednak te wytyczne muszą zostać naruszone, preferowaną metodą jest wywołanie GetAwaiter().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 klasy ICommand. 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 ListViewelementu . Aby uzyskać więcej informacji, zobacz Xamarin.Forms CollectionView.

Optymalizowanie wydajności elementu ListView

W przypadku korzystania z programu ListViewistnieje 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 truewartość . 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 nullma 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.