Ресурсы и стили

Концепция ресурсов в Xamarin Forms

Последнее обновление: 12.01.2021

Для совместного использования одних и тех теж компонентов различными элементами Xamarin Forms применяет концепцию ресурсов. В данном случае под ресурсами понимаются не вспомогательные файлы - изображений и т.д., которые используются в приложении, а логические ресурсы, которые определяются в коде C# или XAML.

Определение ресурсов

В качестве ресурса можно определить любой объект. Все ресурсы помещаются в объект ResourceDictionary. У каждого визуального объекта, например, ContentPage или Button, имеется свойство Resources, которое как раз хранит объект ResourceDictionary. Например, определим несколько ресурсов:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="HelloApp.MainPage">
  <ContentPage.Resources>
    <ResourceDictionary>
      <Color x:Key="textColor">#004D40</Color>
      <Color x:Key="backColor">#80CBC4</Color>
	  <x:Double x:Key="fontSize">24</x:Double>
    </ResourceDictionary>
  </ContentPage.Resources>
  <StackLayout>
    <Button Text="iOS" TextColor="{StaticResource Key=textColor}" 
      BackgroundColor="{StaticResource Key=backColor}" FontSize="{StaticResource Key=fontSize}" />
    <Button Text="Android" TextColor="{StaticResource Key=textColor}" 
      BackgroundColor="{StaticResource Key=backColor}" FontSize="{StaticResource Key=fontSize}" />
  </StackLayout>
</ContentPage>

Каждый ресурс должен иметь ключ, задаваемый с помощью атрибута x:Key. Это своего рода уникальный идентификатор ресурса. Например:

<Color x:Key="textColor">#004D40</Color>

Здесь в качестве ресурса определяется объект Color. Этот объект имеет ключ textColor и значение #004D40.

Чтобы обратиться к этому ресурсу в коде, надо использовать расширение StaticResource:

TextColor="{StaticResource Key=textColor}"

Свойство Key через ключ ресурса будет ссылаться на данный ресурс.

То есть в итоге получится следующая страница:

Статические ресурсы в Xamarin Forms

При этом важно, что на данный ресурс могут ссылаться сразу несколько элементов. Например, мы захотели создать общий для всех кнопок цвет фона. И в этом случае проще определить цветовой ресурс, чем присваивать свойству BackgroundColor у каждой кнопки конкретный цвет. А в случае, если мы захотим изметь цвет кнопок на другой, то не надо будет менять свойство BackgroundColor у всех кнопок. Достаточно будет поменять значение ресурса.

В то же время при старте приложения ему требуется некоторое время, чтобы найти нужные ресурсы. Поэтому использование ресурсов по сравнению со стандартными значениями немного замедляют работу приложения.

Специфичные для платформы ресурсы

С помощью ресурсов можно задать легко управлять визуальными параметрами (например, цветом, отступами и т.д.), которые должны быть специфичными для отдельным платформ:

<ContentPage.Resources>
	<ResourceDictionary>
		<OnPlatform x:Key="textColor"
			x:TypeArguments="Color"
			iOS="Red"
			Android="Green"
			WinPhone="Blue" />
		<Color x:Key="backColor">#e1e1e1</Color>
		<x:Double x:Key="fontSize">22</x:Double>
	</ResourceDictionary>
</ContentPage.Resources>

В данном случае в качестве ресурса определяется элемент OnPlatform, а через его атрибуты Android, iOS, WinPhone задаются значения для конкретных платформ.

Уровни ресурсов

Ресурсы могут определяться на трех уровнях:

  • На уровне отдельного элемента управления. Такие ресурсы могут применяться ко всем вложенным элементам, которые определены внутри этого элемента

  • На уровне всей страницы. Такие ресурсы могут применяться ко всем элементам на странице

  • На уровне всего приложения. Эти ресурсы доступы из любого места и из любой страницы приложения.

Выше в примере ресурсы определялись а уровне страницы. Теперь опустимся на уровень ниже и определим их на уровне элемента StackLayout:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
	xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
	x:Class="HelloApp.MainPage">
	<StackLayout>
		<StackLayout.Resources>
			<ResourceDictionary>
				<Color x:Key="textColor">#004D40</Color>
				<Color x:Key="backColor">#80CBC4</Color>
				<x:Double x:Key="fontSize">22</x:Double>
			</ResourceDictionary>
		</StackLayout.Resources>
		<Button Text="iOS" TextColor="{StaticResource Key=textColor}"
			BackgroundColor="{StaticResource Key=backColor}"  FontSize="{StaticResource Key=fontSize}" />
		<Button Text="Android" TextColor="{StaticResource Key=textColor}"
			 BackgroundColor="{StaticResource Key=backColor}"  FontSize="{StaticResource Key=fontSize}" />
	</StackLayout>
</ContentPage>

По сути результат в данном случае будет от же самый, так как все элементы все равно определены внутри StackLayout.

Ресурсы приложения

Для определения общих для всего приложения ресурсов в проекте присутствует файл App.xaml, который связан с основным файлом приложения App.xaml.cs. Изменим файл App.xaml следующим образом:

<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="HelloApp.App">
	<Application.Resources>

        <ResourceDictionary>
            <Color x:Key="textColor">#004D40</Color>
            <Color x:Key="backColor">#80CBC4</Color>
            <x:Double x:Key="fontSize">22</x:Double>
        </ResourceDictionary>

    </Application.Resources>
</Application>

То есть здесь определены все те же ресурсы, что и ранее, только теперь они будут доступны для любого элемента на любой стрнице внутри приложения.

И в этом случае мы просто можем их использовать:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="HelloApp.MainPage">
    <StackLayout>
        <Button Text="iOS" TextColor="{StaticResource Key=textColor}"
      BackgroundColor="{StaticResource Key=backColor}"  FontSize="{StaticResource Key=fontSize}" />
        <Button Text="Android" TextColor="{StaticResource Key=textColor}"
      BackgroundColor="{StaticResource Key=backColor}"  FontSize="{StaticResource Key=fontSize}" />
    </StackLayout>

</ContentPage>

Управление ресурсами в коде C#

Аналогичный пример использования ресурсов выглядел бы следующим образом:

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        Color textColor = Color.FromRgb(0, 77, 64);
        Color backColor = Color.FromRgb(128, 203, 196);
        Double fontSize = 21;
        ResourceDictionary resDict = new ResourceDictionary();
		// добавляем ресурсы в словарь
        resDict.Add("textColor", textColor);
        resDict.Add("backColor", backColor);
        resDict.Add("fontSize", fontSize);
		// устанавливаем словарь ресурсов
        this.Resources = resDict;

        Button iosButton = new Button { Text = "iOS" };
		// получаем ресурс из словаря
        iosButton.TextColor = (Color)Resources["textColor"];
        iosButton.BackgroundColor = (Color)Resources["backColor"];
        iosButton.FontSize = (double)Resources["fontSize"];

        Button androidButton = new Button { Text = "Android" };
        androidButton.TextColor = (Color)Resources["textColor"];
        androidButton.BackgroundColor = (Color)Resources["backColor"];
        androidButton.FontSize = (double)Resources["fontSize"];

        Content = new StackLayout
        {
            Children = {iosButton, androidButton}
        };
    }
}

Для управления ресурсами применяются методы и свойства ResourceDictionary:

  • Add(string key, object resource): добавляет объект с ключом key в словарь, причем в словарь можно добавить любой объект, главное ему сопоставить ключ

  • Remove(string key): удаляет из словаря ресурс с ключом key

Чтобы найти ресурс в словаре, достаточно обратиться по ключу:

androidButton.TextColor = (Color)Resources["textColor"];

Так как словарь ресурсов хранит объекты типа object, то при получении ресурса его надо привести к нужному типу.

Динамические ресурсы

Ресурсы могут быть статическими и динамическими. Рассмотрим разницу на примере:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="HelloApp.MainPage">
  <ContentPage.Resources>
    <ResourceDictionary>
      <Color x:Key="textColor">Red</Color>
    </ResourceDictionary>
  </ContentPage.Resources>
  <StackLayout>
    <Button Text="Изменить" Clicked="ColorChange" TextColor="{StaticResource Key=textColor}" />
  </StackLayout>
</ContentPage>

В файле кода C# добавим обработчик для кнопки:

private void ColorChange(object sender, EventArgs e)
{
    Color textColor = (Color)Resources["textColor"];
    Resources["textColor"] = textColor == Color.Red ? Color.Green : Color.Red;
}

То есть здесь у кнопки цвет текста привязан к ресурсу "textColor". В обработчике кнопки мы пытаемся поменять значение ресурса - если цвет красный, то меняем на зеленый и наоборот.

Однако после запуска приложения и нажатия на кнопку кнопка не поменяет цвет текста, так как ресурс "textColor" установлен как статический. То есть после установки он уже не изменяется. И чтобы изменение срабатывало, данный ресурс надо установить как динамический. Для этого вместо StaticResource используется расширение DynamicResource:

<Button Text="Изменить" Clicked="ColorChange" TextColor="{DynamicResource Key=textColor}" />

Весь остальной код остается без изменений.

Стоит отметить, что если DynamicResource не найдет нужного ресурса по ключу, то никакой ошибки не возникнет, и приложение также будет работать.

Для установки динамического ресурса в коде применяется метод SetDynamicResource():

button1.SetDynamicResource(Button.TextColorProperty, "resourceKey");

Первый параметр - свойство элемента, а второй - ключ ресурса. Например:

using System;
using Xamarin.Forms;

namespace HelloApp
{
	public partial class MainPage : ContentPage
	{
		public MainPage()
		{
            Color textColor = Color.Red;
            ResourceDictionary resDict = new ResourceDictionary();
            // добавляем ресурсы в словарь
            resDict.Add("textColor", textColor);

            // устанавливаем словарь ресурсов
            this.Resources = resDict;
            
            Button androidButton = new Button { Text = "Android" };
            androidButton.SetDynamicResource(Button.TextColorProperty, "textColor");
            androidButton.Clicked += ColorChange;

            Content = new StackLayout
            {
                Children = { androidButton }
            };
        }
        private void ColorChange(object sender, EventArgs e)
        {
            Color textColor = (Color)Resources["textColor"];
            Resources["textColor"] = textColor == Color.Red ? Color.Green : Color.Red;
        }
    }
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850