Поделиться через


Xamarin.Forms Кнопку

Кнопка реагирует на касание или нажатие, которое направляет приложение для выполнения конкретной задачи.

Самый Button фундаментальный интерактивный элемент управления во всем Xamarin.Forms. Обычно Button отображается короткая текстовая строка, указывающая команду, но она также может отображать растровое изображение или сочетание текста и изображения. Пользователь нажимает Button пальцем или щелкает его мышью, чтобы инициировать следующую команду.

Обработка нажатий кнопки

Button определяет событие, которое запускается, когда пользователь нажимает ClickedButton указатель мыши или пальцем. Событие запускается при освобождении пальца или кнопки мыши из поверхности.Button Для Button ответа на касания должны быть заданы true его IsEnabled свойства.

На странице "Базовый нажатие кнопки " в примере показано, как создать экземпляр Button xaml и обработать его Clicked событие. Файл BasicButtonClickPage.xaml содержит как aStackLayout, так Label и :Button

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ButtonDemos.BasicButtonClickPage"
             Title="Basic Button Click">
    <StackLayout>

        <Label x:Name="label"
               Text="Click the Button below"
               FontSize="Large"
               VerticalOptions="CenterAndExpand"
               HorizontalOptions="Center" />

        <Button Text="Click to Rotate Text!"
                VerticalOptions="CenterAndExpand"
                HorizontalOptions="Center"
                Clicked="OnButtonClicked" />

    </StackLayout>
</ContentPage>

Как Button правило, занимает все пространство, которое разрешено для него. Например, если свойство не задано HorizontalOptionsButton как другое Fill, Button будет занимать полную ширину родительского элемента.

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

Свойство Text указывает текст, отображаемый в Button. Событие Clicked имеет имя обработчика OnButtonClickedсобытий. Этот обработчик находится в файле программной части BasicButtonClickPage.xaml.cs:

public partial class BasicButtonClickPage : ContentPage
{
    public BasicButtonClickPage ()
    {
        InitializeComponent ();
    }

    async void OnButtonClicked(object sender, EventArgs args)
    {
        await label.RelRotateTo(360, 1000);
    }
}

При касании Button выполняется метод OnButtonClicked. Аргумент sender является объектом, Button ответственным за это событие. Это можно использовать для доступа к объекту Button или для различения нескольких Button объектов, использующих одно и то же Clicked событие.

Этот конкретный Clicked обработчик вызывает функцию анимации, которая поворачивает Label 360 градусов в 1000 миллисекундах. Вот программа, запущенная на устройствах iOS и Android, а также в качестве приложения универсальная платформа Windows (UWP) на рабочем столе Windows 10:

Нажатие кнопки

Обратите внимание, что метод OnButtonClicked включает async модификатор, так как await используется в обработчике событий. Обработчик Clicked событий требует async модификатора только в том случае, если текст обработчика используется await.

Каждая платформа выполняет отрисовку Button собственного конкретного способа. В разделе "Внешний вид кнопки" вы увидите, как задать цвета и сделать границу видимой Button для более настраиваемых внешних видов. ButtonIFontElement реализует интерфейс, поэтому он включает FontFamilyFontSizeи FontAttributes свойства.

Создание кнопки в коде

Обычно создается экземпляр Button xaml, но вы также можете создать его в коде Button . Это может быть удобно, если приложению нужно создать несколько кнопок на основе данных, которые можно перечислить циклом foreach .

На странице нажатия кнопки кода показано, как создать страницу, которая функционально эквивалентна странице "Базовый нажатие кнопки", но полностью в C#:

public class CodeButtonClickPage : ContentPage
{
    public CodeButtonClickPage ()
    {
        Title = "Code Button Click";

        Label label = new Label
        {
            Text = "Click the Button below",
            FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
            VerticalOptions = LayoutOptions.CenterAndExpand,
            HorizontalOptions = LayoutOptions.Center
        };

        Button button = new Button
        {
            Text = "Click to Rotate Text!",
            VerticalOptions = LayoutOptions.CenterAndExpand,
            HorizontalOptions = LayoutOptions.Center
        };
        button.Clicked += async (sender, args) => await label.RelRotateTo(360, 1000);

        Content = new StackLayout
        {
            Children =
            {
                label,
                button
            }
        };
    }
}

Все выполняется в конструкторе класса. Clicked Так как обработчик имеет длину только одного оператора, его можно подключить к событию очень просто:

button.Clicked += async (sender, args) => await label.RelRotateTo(360, 1000);

Конечно, можно также определить обработчик событий как отдельный метод (как OnButtonClick и метод в базовом нажатии кнопки) и присоединить этот метод к событию:

button.Clicked += OnButtonClicked;

Отключение кнопки

Иногда приложение находится в определенном состоянии, в котором конкретный Button щелчок не является допустимой операцией. В таких случаях следует отключить, Button задав для свойства значение falseIsEnabled . Классический Entry пример — это элемент управления для имени файла, сопровождаемого файлом открытия Buttonфайла: Button его следует включить только в том случае, если некоторый текст был введен в файл Entry. Эту задачу можно использовать DataTrigger , как показано в статье "Триггеры данных".

Использование интерфейса команды

Приложение может реагировать на Button касания без обработки Clicked события. Реализует Button альтернативный механизм уведомлений, называемый командой или интерфейсом команд . Это состоит из двух свойств:

Этот подход особенно подходит в связи с привязкой данных, и особенно при реализации архитектуры Model-View-ViewModel (MVVM). Эти разделы рассматриваются в статьях "Привязка данных", "От привязок данных к MVVM" и MVVM.

В приложении MVVM модель представления определяет свойства типа ICommand , которые затем подключаются к элементам XAML Button с привязками данных. Xamarin.Formsтакже определяет и классыCommand, реализующие ICommand интерфейс и помогающие модели представления в определении свойств типаICommand.Command<T>

Команды подробно описаны в статье "Интерфейс команд", но на странице "Базовая кнопка" в примере показан базовый подход.

Класс CommandDemoViewModel представляет собой очень простую модель представления, которая определяет свойство типа double с именем, а также два свойства типа ICommand с именем NumberMultiplyBy2Command иDivideBy2Command:

class CommandDemoViewModel : INotifyPropertyChanged
{
    double number = 1;

    public event PropertyChangedEventHandler PropertyChanged;

    public CommandDemoViewModel()
    {
        MultiplyBy2Command = new Command(() => Number *= 2);

        DivideBy2Command = new Command(() => Number /= 2);
    }

    public double Number
    {
        set
        {
            if (number != value)
            {
                number = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Number"));
            }
        }
        get
        {
            return number;
        }
    }

    public ICommand MultiplyBy2Command { private set; get; }

    public ICommand DivideBy2Command { private set; get; }
}

Два ICommand свойства инициализированы в конструкторе класса с двумя объектами типа Command. Конструкторы Command включают небольшую функцию (называется execute аргументом конструктора), которая либо двойнит, либо половины Number свойства.

Файл BasicButtonCommand.xaml задает его BindingContext экземпляру CommandDemoViewModel. Элемент Label и два Button элемента содержат привязки к трем свойствам:CommandDemoViewModel

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ButtonDemos"
             x:Class="ButtonDemos.BasicButtonCommandPage"
             Title="Basic Button Command">

    <ContentPage.BindingContext>
        <local:CommandDemoViewModel />
    </ContentPage.BindingContext>

    <StackLayout>
        <Label Text="{Binding Number, StringFormat='Value is now {0}'}"
               FontSize="Large"
               VerticalOptions="CenterAndExpand"
               HorizontalOptions="Center" />

        <Button Text="Multiply by 2"
                VerticalOptions="CenterAndExpand"
                HorizontalOptions="Center"
                Command="{Binding MultiplyBy2Command}" />

        <Button Text="Divide by 2"
                VerticalOptions="CenterAndExpand"
                HorizontalOptions="Center"
                Command="{Binding DivideBy2Command}" />
    </StackLayout>
</ContentPage>

По мере касания двух Button элементов выполняются команды и значение числа изменений:

Команда

Преимущество этого подхода по сравнению Clicked с обработчиками заключается в том, что все логики, связанные с функциональностью этой страницы, находятся в режиме просмотра, а не в файле программной части, что обеспечивает лучшее разделение пользовательского интерфейса от бизнес-логики.

Кроме того, объекты могут Command управлять включением и отключением Button элементов. Например, предположим, что необходимо ограничить диапазон значений числа от 2до 1010. Вы можете добавить другую функцию в конструктор (называемый аргументом canExecute ), которая возвращает true , если она должна быть включена Button . Ниже приведено изменение конструктора CommandDemoViewModel :

class CommandDemoViewModel : INotifyPropertyChanged
{
    ···
    public CommandDemoViewModel()
    {
        MultiplyBy2Command = new Command(
            execute: () =>
            {
                Number *= 2;
                ((Command)MultiplyBy2Command).ChangeCanExecute();
                ((Command)DivideBy2Command).ChangeCanExecute();
            },
            canExecute: () => Number < Math.Pow(2, 10));

        DivideBy2Command = new Command(
            execute: () =>
            {
                Number /= 2;
                ((Command)MultiplyBy2Command).ChangeCanExecute();
                ((Command)DivideBy2Command).ChangeCanExecute();
            },
            canExecute: () => Number > Math.Pow(2, -10));
    }
    ···
}

Вызовы ChangeCanExecute метода Command необходимы, чтобы Command метод можно было вызвать canExecute метод и определить, следует ли Button отключить или нет. При изменении этого кода число достигает предела, оно Button отключено:

Команда

Для двух или нескольких Button элементов можно привязать к одному ICommand свойству. Элементы Button можно различать с помощью CommandParameter свойства Button. В этом случае необходимо использовать универсальный Command<T> класс. Затем CommandParameter объект передается в качестве аргумента execute в методы и canExecute методы. Этот метод подробно показан в разделе "Базовый команд" статьи "Интерфейс командной строки".

В примере также используется этот метод в своем MainPage классе. Файл MainPage.xaml содержит Button для каждой страницы примера:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ButtonDemos"
             x:Class="ButtonDemos.MainPage"
             Title="Button Demos">
    <ScrollView>
        <FlexLayout Direction="Column"
                    JustifyContent="SpaceEvenly"
                    AlignItems="Center">

            <Button Text="Basic Button Click"
                    Command="{Binding NavigateCommand}"
                    CommandParameter="{x:Type local:BasicButtonClickPage}" />

            <Button Text="Code Button Click"
                    Command="{Binding NavigateCommand}"
                    CommandParameter="{x:Type local:CodeButtonClickPage}" />

            <Button Text="Basic Button Command"
                    Command="{Binding NavigateCommand}"
                    CommandParameter="{x:Type local:BasicButtonCommandPage}" />

            <Button Text="Press and Release Button"
                    Command="{Binding NavigateCommand}"
                    CommandParameter="{x:Type local:PressAndReleaseButtonPage}" />

            <Button Text="Button Appearance"
                    Command="{Binding NavigateCommand}"
                    CommandParameter="{x:Type local:ButtonAppearancePage}" />

            <Button Text="Toggle Button Demo"
                    Command="{Binding NavigateCommand}"
                    CommandParameter="{x:Type local:ToggleButtonDemoPage}" />

            <Button Text="Image Button Demo"
                    Command="{Binding NavigateCommand}"
                    CommandParameter="{x:Type local:ImageButtonDemoPage}" />

        </FlexLayout>
    </ScrollView>
</ContentPage>

Каждое Button свойство привязано Command к свойству с именем NavigateCommand, и CommandParameter для него задан Type объект, соответствующий одному из классов страниц в проекте.

Это NavigateCommand свойство имеет тип ICommand и определяется в файле кода программной части:

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();

        NavigateCommand = new Command<Type>(async (Type pageType) =>
        {
            Page page = (Page)Activator.CreateInstance(pageType);
            await Navigation.PushAsync(page);
        });

        BindingContext = this;
    }

    public ICommand NavigateCommand { private set; get; }
}

Конструктор инициализирует NavigateCommand свойство Command<Type> объекту, так как Type является типом CommandParameter объекта, заданного в XAML-файле. Это означает, что execute метод имеет аргумент типа Type , соответствующий этому CommandParameter объекту. Функция создает экземпляр страницы, а затем переходит к ней.

Обратите внимание, что конструктор завершается установкой для BindingContext себя. Это необходимо для свойств в XAML-файле для привязки к свойству NavigateCommand .

Нажатие и освобождение кнопки

Помимо события ClickedButton также определяет события Pressed и Released. Это Pressed событие возникает, когда пальцем нажимает клавишу Button, или кнопка мыши нажимается указателем, расположенным над ним Button. Событие Released возникает при освобождении пальца или кнопки мыши. Как правило, Clicked событие также запускается Released одновременно с событием, но если указатель мыши или пальцем скользит от поверхности Button перед освобождением, Clicked событие может не произойти.

Часто Pressed используются и Released события, но их можно использовать для специальных целей, как показано на странице "Кнопка нажатия и выпуска". XAML-файл содержит Label обработчики, подключенные к Pressed событиям и ButtonReleased событиям:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ButtonDemos.PressAndReleaseButtonPage"
             Title="Press and Release Button">
    <StackLayout>

        <Label x:Name="label"
               Text="Press and hold the Button below"
               FontSize="Large"
               VerticalOptions="CenterAndExpand"
               HorizontalOptions="Center" />

        <Button Text="Press to Rotate Text!"
                VerticalOptions="CenterAndExpand"
                HorizontalOptions="Center"
                Pressed="OnButtonPressed"
                Released="OnButtonReleased" />

    </StackLayout>
</ContentPage>

Файл программной части анимирует LabelPressed событие при возникновении события, но приостанавливает поворот при Released возникновении события:

public partial class PressAndReleaseButtonPage : ContentPage
{
    bool animationInProgress = false;
    Stopwatch stopwatch = new Stopwatch();

    public PressAndReleaseButtonPage ()
    {
        InitializeComponent ();
    }

    void OnButtonPressed(object sender, EventArgs args)
    {
        stopwatch.Start();
        animationInProgress = true;

        Device.StartTimer(TimeSpan.FromMilliseconds(16), () =>
        {
            label.Rotation = 360 * (stopwatch.Elapsed.TotalSeconds % 1);

            return animationInProgress;
        });
    }

    void OnButtonReleased(object sender, EventArgs args)
    {
        animationInProgress = false;
        stopwatch.Stop();
    }
}

Результатом является то, что Label только поворачивается, пока пальцем контактирует с Button, и останавливается при освобождении пальца:

Нажмите и отпустите кнопку

Такое поведение имеет приложения для игр: палец, удерживаемый на Button экране, может сделать перемещение объекта на экране в определенном направлении.

Внешний вид кнопки

Наследуется Button или определяет несколько свойств, влияющих на его внешний вид:

  • TextColor — это цвет Button текста
  • BackgroundColor — цвет фона для этого текста
  • BorderColor цвет области вокруг Button
  • FontFamily — семейство шрифтов, используемое для текста
  • FontSize — это размер текста
  • FontAttributes указывает, является ли текст курсивным или полужирным
  • BorderWidth — ширина границы
  • CornerRadius — это угол радиуса Button
  • CharacterSpacing — интервал между символами Button текста.
  • TextTransform определяет регистр Button текста.

Примечание.

Класс Button также имеет Margin и Padding свойства, которые управляют поведением макета Buttonобъекта. Дополнительные сведения см. в статье Поля и заполнение.

Эффекты шести из этих свойств (за исключением FontFamily и FontAttributes) показаны на странице "Внешний вид кнопки". Другое свойство, Imageописано в разделе "Использование растровых карт с кнопкой".

Все представления и привязки данных на странице "Внешний вид кнопки" определяются в XAML-файле:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ButtonDemos"
             x:Class="ButtonDemos.ButtonAppearancePage"
             Title="Button Appearance">
    <StackLayout>
        <Button x:Name="button"
                Text="Button"
                VerticalOptions="CenterAndExpand"
                HorizontalOptions="Center"
                TextColor="{Binding Source={x:Reference textColorPicker},
                                    Path=SelectedItem.Color}"
                BackgroundColor="{Binding Source={x:Reference backgroundColorPicker},
                                          Path=SelectedItem.Color}"
                BorderColor="{Binding Source={x:Reference borderColorPicker},
                                      Path=SelectedItem.Color}" />

        <StackLayout BindingContext="{x:Reference button}"
                     Padding="10">

            <Slider x:Name="fontSizeSlider"
                    Maximum="48"
                    Minimum="1"
                    Value="{Binding FontSize}" />

            <Label Text="{Binding Source={x:Reference fontSizeSlider},
                                  Path=Value,
                                  StringFormat='FontSize = {0:F0}'}"
                   HorizontalTextAlignment="Center" />

            <Slider x:Name="borderWidthSlider"
                    Minimum="-1"
                    Maximum="12"
                    Value="{Binding BorderWidth}" />

            <Label Text="{Binding Source={x:Reference borderWidthSlider},
                                  Path=Value,
                                  StringFormat='BorderWidth = {0:F0}'}"
                   HorizontalTextAlignment="Center" />

            <Slider x:Name="cornerRadiusSlider"
                    Minimum="-1"
                    Maximum="24"
                    Value="{Binding CornerRadius}" />

            <Label Text="{Binding Source={x:Reference cornerRadiusSlider},
                                  Path=Value,
                                  StringFormat='CornerRadius = {0:F0}'}"
                   HorizontalTextAlignment="Center" />

            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>

                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>

                <Grid.Resources>
                    <Style TargetType="Label">
                        <Setter Property="VerticalOptions" Value="Center" />
                    </Style>
                </Grid.Resources>

                <Label Text="Text Color:"
                       Grid.Row="0" Grid.Column="0" />

                <Picker x:Name="textColorPicker"
                        ItemsSource="{Binding Source={x:Static local:NamedColor.All}}"
                        ItemDisplayBinding="{Binding FriendlyName}"
                        SelectedIndex="0"
                        Grid.Row="0" Grid.Column="1" />

                <Label Text="Background Color:"
                       Grid.Row="1" Grid.Column="0" />

                <Picker x:Name="backgroundColorPicker"
                        ItemsSource="{Binding Source={x:Static local:NamedColor.All}}"
                        ItemDisplayBinding="{Binding FriendlyName}"
                        SelectedIndex="0"
                        Grid.Row="1" Grid.Column="1" />

                <Label Text="Border Color:"
                       Grid.Row="2" Grid.Column="0" />

                <Picker x:Name="borderColorPicker"
                        ItemsSource="{Binding Source={x:Static local:NamedColor.All}}"
                        ItemDisplayBinding="{Binding FriendlyName}"
                        SelectedIndex="0"
                        Grid.Row="2" Grid.Column="1" />
            </Grid>
        </StackLayout>
    </StackLayout>
</ContentPage>

В Button верхней части страницы есть три Color свойства, привязанные к Picker элементам в нижней части страницы. Элементы в Picker элементах — это цвета из NamedColor класса, включенного в проект. Три Slider элемента содержат двусторонняя привязка к FontSizeи BorderWidthCornerRadius свойствам объектаButton.

Эта программа позволяет экспериментировать с сочетаниями всех этих свойств:

Внешний вид кнопки

Чтобы увидеть границу Button , необходимо задать BorderColor значение, отличное Defaultот значения, а BorderWidth также положительное значение.

В iOS вы заметите, что большая ширина границы встраивается в интерьер и Button вмешивается в отображение текста. Если вы решили использовать границу с iOS Button, вам, вероятно, нужно начать и завершить Text свойство пробелами, чтобы сохранить ее видимость.

В UWP выберите значение CornerRadius , превышающее половину высоты Button возникающего исключения.

Визуальные состояния кнопки

Button имеет значение PressedVisualState , которое можно использовать для запуска визуального изменения Button при нажатии пользователем, если оно включено.

В следующем примере XAML показано, как определить визуальное состояние для Pressed состояния:

<Button Text="Click me!"
        ...>
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="CommonStates">
            <VisualState x:Name="Normal">
                <VisualState.Setters>
                    <Setter Property="Scale"
                            Value="1" />
                </VisualState.Setters>
            </VisualState>

            <VisualState x:Name="Pressed">
                <VisualState.Setters>
                    <Setter Property="Scale"
                            Value="0.8" />
                </VisualState.Setters>
            </VisualState>

        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Button>

Указывает PressedVisualState , что при Button нажатии нажатия его Scale свойство будет изменено со значения по умолчанию от 1 до 0,8. Указывает NormalVisualState , что при Button обычном состоянии его Scale свойство будет иметь значение 1. Таким образом, общий эффект заключается в том, что при Button нажатии она будет немного меньше, а при Button выпуске она будет масштабирована до размера по умолчанию.

Дополнительные сведения о визуальных состояниях см. в разделе "Диспетчер визуальных состоянийXamarin.Forms".

Создание кнопки переключения

Можно подкласс Button , чтобы он работал как выключенный переключатель: коснитесь кнопки один раз, чтобы переключить кнопку и снова коснитесь ее, чтобы отключить его.

ToggleButton Следующий класс является производным от Button и определяет новое событие с именем Toggled и логическим свойством.IsToggled Это те же два свойства, определенные в следующих Xamarin.FormsSwitchсвойствах:

class ToggleButton : Button
{
    public event EventHandler<ToggledEventArgs> Toggled;

    public static BindableProperty IsToggledProperty =
        BindableProperty.Create("IsToggled", typeof(bool), typeof(ToggleButton), false,
                                propertyChanged: OnIsToggledChanged);

    public ToggleButton()
    {
        Clicked += (sender, args) => IsToggled ^= true;
    }

    public bool IsToggled
    {
        set { SetValue(IsToggledProperty, value); }
        get { return (bool)GetValue(IsToggledProperty); }
    }

    protected override void OnParentSet()
    {
        base.OnParentSet();
        VisualStateManager.GoToState(this, "ToggledOff");
    }

    static void OnIsToggledChanged(BindableObject bindable, object oldValue, object newValue)
    {
        ToggleButton toggleButton = (ToggleButton)bindable;
        bool isToggled = (bool)newValue;

        // Fire event
        toggleButton.Toggled?.Invoke(toggleButton, new ToggledEventArgs(isToggled));

        // Set the visual state
        VisualStateManager.GoToState(toggleButton, isToggled ? "ToggledOn" : "ToggledOff");
    }
}

Конструктор ToggleButton присоединяет обработчик к Clicked событию, чтобы он смог изменить значение IsToggled свойства. Метод OnIsToggledChanged запускает Toggled событие.

Последняя строка OnIsToggledChanged метода вызывает статический VisualStateManager.GoToState метод с двумя текстовыми строками ToggledOn и ToggledOff. Вы можете ознакомиться с этим методом и о том, как приложение может реагировать на визуальные состояния в статье Диспетчер визуальных состояний.Xamarin.Forms

Так как ToggleButton вызывается VisualStateManager.GoToState, самому классу не нужно включать дополнительные средства для изменения внешнего вида кнопки на основе его IsToggled состояния. Это ответственность за XAML, на котором размещается ToggleButtonобъект .

На странице демонстрации кнопки переключателя содержатся два экземпляра разметки, включая разметку диспетчера визуальных ToggleButtonсостояний, задающую TextBackgroundColorTextColor и кнопку на основе визуального состояния:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ButtonDemos"
             x:Class="ButtonDemos.ToggleButtonDemoPage"
             Title="Toggle Button Demo">

    <ContentPage.Resources>
        <Style TargetType="local:ToggleButton">
            <Setter Property="VerticalOptions" Value="CenterAndExpand" />
            <Setter Property="HorizontalOptions" Value="Center" />
        </Style>
    </ContentPage.Resources>

    <StackLayout Padding="10, 0">
        <local:ToggleButton Toggled="OnItalicButtonToggled">
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup Name="ToggleStates">
                    <VisualState Name="ToggledOff">
                        <VisualState.Setters>
                            <Setter Property="Text" Value="Italic Off" />
                            <Setter Property="BackgroundColor" Value="#C0C0C0" />
                            <Setter Property="TextColor" Value="Black" />
                        </VisualState.Setters>
                    </VisualState>

                    <VisualState Name="ToggledOn">
                        <VisualState.Setters>
                            <Setter Property="Text" Value=" Italic On " />
                            <Setter Property="BackgroundColor" Value="#404040" />
                            <Setter Property="TextColor" Value="White" />
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
        </local:ToggleButton>

        <local:ToggleButton Toggled="OnBoldButtonToggled">
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup Name="ToggleStates">
                    <VisualState Name="ToggledOff">
                        <VisualState.Setters>
                            <Setter Property="Text" Value="Bold Off" />
                            <Setter Property="BackgroundColor" Value="#C0C0C0" />
                            <Setter Property="TextColor" Value="Black" />
                        </VisualState.Setters>
                    </VisualState>

                    <VisualState Name="ToggledOn">
                        <VisualState.Setters>
                            <Setter Property="Text" Value=" Bold On " />
                            <Setter Property="BackgroundColor" Value="#404040" />
                            <Setter Property="TextColor" Value="White" />
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
        </local:ToggleButton>

        <Label x:Name="label"
               Text="Just a little passage of some sample text that can be formatted in italic or boldface by toggling the two buttons."
               FontSize="Large"
               HorizontalTextAlignment="Center"
               VerticalOptions="CenterAndExpand" />

    </StackLayout>
</ContentPage>

Обработчики Toggled событий находятся в файле кода программной части. Они отвечают за задание FontAttributes свойства Label на основе состояния кнопок:

public partial class ToggleButtonDemoPage : ContentPage
{
    public ToggleButtonDemoPage ()
    {
        InitializeComponent ();
    }

    void OnItalicButtonToggled(object sender, ToggledEventArgs args)
    {
        if (args.Value)
        {
            label.FontAttributes |= FontAttributes.Italic;
        }
        else
        {
            label.FontAttributes &= ~FontAttributes.Italic;
        }
    }

    void OnBoldButtonToggled(object sender, ToggledEventArgs args)
    {
        if (args.Value)
        {
            label.FontAttributes |= FontAttributes.Bold;
        }
        else
        {
            label.FontAttributes &= ~FontAttributes.Bold;
        }
    }
}

Ниже приведена программа, запущенная в iOS, Android и UWP:

Демонстрация переключателя кнопки

Использование растровых изображений в кнопках

Класс Button определяет ImageSource свойство, которое позволяет отображать растровое изображение в Buttonодном или в сочетании с текстом. Вы также можете указать порядок упорядочения текста и изображения.

Свойство ImageSource имеет тип ImageSource, что означает, что растровые изображения можно загружать из файла, внедренного ресурса, URI или потока.

Примечание.

Button Хотя можно загрузить анимированный GIF-файл, он будет отображать только первый кадр GIF.

Каждая платформа, поддерживаемая с помощью Xamarin.Forms изображений, может храниться в нескольких размерах для разных разрешений пикселей различных устройств, на которых может работать приложение. Эти несколько растровых карт именуются или хранятся таким образом, чтобы операционная система может выбрать оптимальное соответствие для разрешения дисплея видео устройства.

Для растрового Buttonизображения лучшего размера обычно составляет от 32 до 64 единиц, независимых от устройства, в зависимости от того, насколько большой размер он должен быть. Изображения, используемые в этом примере, основаны на размере 48 независимых от устройств единиц.

В проекте iOS папка Resources содержит три размера этого образа:

  • 48-пиксельная квадратная растровая карта, сохраненная как /Resources/MonkeyFace.png
  • 96-пиксельная квадратная растровая карта, сохраненная как /Resource/MonkeyFace@2x.png
  • 144-пиксельная квадратная растровая карта, хранящуюся как /Resource/MonkeyFace@3x.png

Все три растровых изображения были предоставлены действие сборки пакетаResource.

Для проекта Android все растровые изображения имеют одно и то же имя, но они хранятся в разных вложенных папках папки Resources :

  • 72-пиксельная квадратная растровая карта, сохраненная как /Resources/drawable-hdpi/MonkeyFace.png
  • 96-пиксельная квадратная растровая карта, сохраненная как /Resources/drawable-xhdpi/MonkeyFace.png
  • 144-пиксельная квадратная растровая карта, сохраненная как /Resources/drawable-xxhdpi/MonkeyFace.png
  • 192-пиксельная квадратная растровая карта, сохраненная как /Resources/drawable-xxxhdpi/MonkeyFace.png

Они были даны действие сборки AndroidResource.

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

  • 48-пиксельная квадратная растровая карта, сохраненная как /Assets/MonkeyFace.scale-100.png
  • 96-пиксельная квадратная растровая карта, сохраненная как /Assets/MonkeyFace.scale-200.png
  • 192-пиксельная квадратная растровая карта, сохраненная как /Assets/MonkeyFace.scale-400.png

Все они получили действие сборки содержимого.

Вы можете указать, как Text упорядочены свойства и ImageSource свойства с Button помощью ContentLayout свойства Button. Это свойство имеет тип ButtonContentLayout, который является внедренным классом в Button. Конструктор имеет два аргумента:

  • Элемент ImagePosition перечисления: Left, TopRightили Bottom указывает, как появляется растровое изображение относительно текста.
  • double Значение интервала между растровым изображением и текстом.

По умолчанию используются Left 10 единиц. Два свойства только для ButtonContentLayout чтения именованных Position и Spacing предоставляют значения этих свойств.

В коде можно создать Button и задать следующее ContentLayout свойство:

Button button = new Button
{
    Text = "button text",
    ImageSource = new FileImageSource
    {
        File = "image filename"
    },
    ContentLayout = new Button.ButtonContentLayout(Button.ButtonContentLayout.ImagePosition.Right, 20)
};

В XAML необходимо указать только элемент перечисления, интервал или оба порядка, разделенные запятыми:

<Button Text="button text"
        ImageSource="image filename"
        ContentLayout="Right, 20" />

Страница демонстрации кнопки изображения используется OnPlatform для указания различных имен файлов для файлов растровых карт iOS, Android и UWP. Если вы хотите использовать одно и то же имя файла для каждой платформы и избежать использования OnPlatform, необходимо сохранить растровые изображения UWP в корневом каталоге проекта.

Первый на странице Button "Демонстрация кнопки изображения" задает Image свойство, но не Text свойство:

<Button>
    <Button.ImageSource>
        <OnPlatform x:TypeArguments="ImageSource">
            <On Platform="iOS, Android" Value="MonkeyFace.png" />
            <On Platform="UWP" Value="Assets/MonkeyFace.png" />
        </OnPlatform>
    </Button.ImageSource>
</Button>

Если растровые карты UWP хранятся в корневом каталоге проекта, эта разметка может быть значительно упрощена:

<Button ImageSource="MonkeyFace.png" />

Чтобы избежать много повторной разметки в файле ImageButtonDemo.xaml , неявное Style также определяется для задания ImageSource свойства. Это Style автоматически применяется к пяти другим Button элементам. Ниже приведен полный XAML-файл:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ButtonDemos.ImageButtonDemoPage">

    <FlexLayout Direction="Column"
                JustifyContent="SpaceEvenly"
                AlignItems="Center">

        <FlexLayout.Resources>
            <Style TargetType="Button">
                <Setter Property="ImageSource">
                    <OnPlatform x:TypeArguments="ImageSource">
                        <On Platform="iOS, Android" Value="MonkeyFace.png" />
                        <On Platform="UWP" Value="Assets/MonkeyFace.png" />
                    </OnPlatform>
                </Setter>
            </Style>
        </FlexLayout.Resources>

        <Button>
            <Button.ImageSource>
                <OnPlatform x:TypeArguments="ImageSource">
                    <On Platform="iOS, Android" Value="MonkeyFace.png" />
                    <On Platform="UWP" Value="Assets/MonkeyFace.png" />
                </OnPlatform>
            </Button.ImageSource>
        </Button>

        <Button Text="Default" />

        <Button Text="Left - 10"
                ContentLayout="Left, 10" />

        <Button Text="Top - 10"
                ContentLayout="Top, 10" />

        <Button Text="Right - 20"
                ContentLayout="Right, 20" />

        <Button Text="Bottom - 20"
                ContentLayout="Bottom, 20" />
    </FlexLayout>
</ContentPage>

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

Демонстрация кнопки изображения

Теперь вы видели различные способы обработки Button событий и изменения Button внешнего вида.