Xamarin.Forms Pulsante

Download Sample Scaricare l'esempio

Il pulsante risponde a un tocco o a un clic che indirizza un'applicazione a eseguire una determinata attività.

Button è il controllo interattivo più fondamentale in tutti .Xamarin.Forms In Button genere viene visualizzata una stringa di testo breve che indica un comando, ma può anche visualizzare un'immagine bitmap o una combinazione di testo e un'immagine. L'utente preme Button con un dito o lo fa clic con un mouse per avviare tale comando.

La maggior parte degli argomenti illustrati di seguito corrisponde alle pagine dell'esempio ButtonDemos .

Gestione dei clic dei pulsanti

Button definisce un Clicked evento generato quando l'utente tocca Button con un dito o un puntatore del mouse. L'evento viene generato quando il dito o il pulsante del mouse viene rilasciato dalla superficie di Button. La Button proprietà deve essere IsEnabled impostata su true affinché risponda ai tap.

La pagina Clic pulsante di base nell'esempio ButtonDemos illustra come creare un'istanza di in Button XAML e gestire il relativo Clicked evento. Il file BasicButtonClickPage.xaml contiene un oggetto StackLayout con un Label oggetto e un Buttonoggetto :

<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>

Tende Button a occupare tutto lo spazio per cui è consentito. Ad esempio, se non si imposta la HorizontalOptions proprietà di Button su un valore diverso Fillda , l'oggetto Button occupa la larghezza intera del relativo elemento padre.

Per impostazione predefinita, è Button rettangolare, ma è possibile assegnargli angoli arrotondati usando la CornerRadius proprietà , come descritto di seguito nella sezione Aspetto pulsante.

La proprietà Text specifica il testo visualizzato nel Button. L'evento Clicked è impostato su un gestore eventi denominato OnButtonClicked. Questo gestore si trova nel file code-behind BasicButtonClickPage.xaml.cs:

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

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

Con il tocco su Button viene eseguito il metodo OnButtonClicked. L'argomento sender è l'oggetto Button responsabile di questo evento. È possibile usarlo per accedere all'oggetto Button o per distinguere tra più Button oggetti che condividono lo stesso Clicked evento.

Questo gestore specifico Clicked chiama una funzione di animazione che ruota i Label 360 gradi in 1000 millisecondi. Ecco il programma in esecuzione nei dispositivi iOS e Android e come applicazione piattaforma UWP (Universal Windows Platform) (UWP) sul desktop di Windows 10:

Basic Button Click

Si noti che il OnButtonClicked metodo include il async modificatore perché await viene usato all'interno del gestore eventi. Un Clicked gestore eventi richiede il async modificatore solo se il corpo del gestore usa await.

Ogni piattaforma esegue il rendering in Button modo specifico. Nella sezione Aspetto pulsante verrà illustrato come impostare i colori e rendere visibile il Button bordo per un aspetto più personalizzato. Button implementa l'interfaccia IFontElement , quindi include FontFamilyle proprietà , FontSizee FontAttributes .

Creazione di un pulsante nel codice

È comune creare un'istanza di in Button XAML, ma è anche possibile creare un Button oggetto nel codice. Ciò potrebbe risultare utile quando l'applicazione deve creare più pulsanti in base ai dati enumerabili con un foreach ciclo.

La pagina Clic pulsante codice illustra come creare una pagina equivalente funzionalmente alla pagina Clic pulsante di base, ma interamente in 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
            }
        };
    }
}

Tutto viene eseguito nel costruttore della classe. Poiché il Clicked gestore è una sola istruzione lunga, può essere collegata all'evento molto semplicemente:

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

Naturalmente, è anche possibile definire il gestore eventi come metodo separato (proprio come il OnButtonClick metodo in Clic pulsante di base) e allegare il metodo all'evento:

button.Clicked += OnButtonClicked;

Disabilitazione del pulsante

In alcuni casi un'applicazione si trova in uno stato specifico in cui un particolare Button clic non è un'operazione valida. In questi casi, l'oggetto Button deve essere disabilitato impostando la relativa IsEnabled proprietà su false. L'esempio classico è un Entry controllo per un nome file accompagnato da un file aperto Button: Button deve essere abilitato solo se un testo è stato digitato in Entry. È possibile usare per DataTrigger questa attività, come illustrato nell'articolo Trigger di dati.

Uso dell'interfaccia del comando

È possibile che un'applicazione risponda ai Button tap senza gestire l'evento Clicked . Button implementa un meccanismo di notifica alternativo denominato comando o interfaccia di comando. Questo è costituito da due proprietà:

Questo approccio è particolarmente adatto in relazione all'associazione dati e in particolare quando si implementa l'architettura MVVM (Model-View-ViewModel). Questi argomenti sono illustrati negli articoli Data Binding, Da data binding a MVVM e MVVM.

In un'applicazione MVVM il modello di visualizzazione definisce le proprietà di tipo ICommand che vengono quindi connesse agli elementi XAML Button con data binding. Xamarin.Forms definisce Command anche le classi e Command<T> che implementano l'interfaccia ICommand e supportano il modello di visualizzazione nella definizione delle proprietà di tipo ICommand.

Il comando è descritto in modo più dettagliato nell'articolo Interfaccia di comando, ma la pagina Comando pulsante di base nell'esempio ButtonDemos illustra l'approccio di base.

La CommandDemoViewModel classe è un modello di visualizzazione molto semplice che definisce una proprietà di tipo double denominato Numbere due proprietà di tipo ICommand denominato MultiplyBy2Command e 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; }
}

Le due ICommand proprietà vengono inizializzate nel costruttore della classe con due oggetti di tipo Command. I Command costruttori includono una piccola funzione (denominata argomento del execute costruttore) che raddoppia o metà la Number proprietà.

Il file BasicButtonCommand.xaml imposta il relativo BindingContext su un'istanza di CommandDemoViewModel. L'elemento Label e due Button elementi contengono associazioni alle tre proprietà in 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>

Man mano che vengono toccati i due Button elementi, vengono eseguiti i comandi e il valore del numero cambia:

Basic Button Command

Il vantaggio di questo approccio rispetto Clicked ai gestori è che tutta la logica che coinvolge la funzionalità di questa pagina si trova nel modello di visualizzazione anziché nel file code-behind, ottenendo una migliore separazione dell'interfaccia utente dalla logica di business.

È anche possibile che gli Command oggetti controllino l'abilitazione e la disabilitazione degli Button elementi. Si supponga, ad esempio, di voler limitare l'intervallo di valori numerici compresi tra 210 e 2-10. È possibile aggiungere un'altra funzione al costruttore (denominato canExecute argomento) che restituisce true se Button deve essere abilitato. Ecco la modifica al CommandDemoViewModel costruttore:

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));
    }
    ···
}

Le chiamate al metodo di Command sono necessarie in modo che il Command metodo possa chiamare il canExecute metodo e determinare se deve Button essere disabilitato o ChangeCanExecute meno. Con questa modifica del codice, man mano che il numero raggiunge il limite, l'oggetto Button è disabilitato:

Basic Button Command - Modified

È possibile associare due o più Button elementi alla stessa ICommand proprietà. Gli Button elementi possono essere distinti usando la CommandParameter proprietà di Button. In questo caso, si vuole usare la classe generica Command<T> . L'oggetto CommandParameter viene quindi passato come argomento ai execute metodi e canExecute . Questa tecnica viene illustrata in dettaglio nella sezione Comandi di base dell'articolo Interfaccia di comando.

L'esempio ButtonDemos usa anche questa tecnica nella relativa MainPage classe. Il file MainPage.xaml contiene una Button per ogni pagina dell'esempio:

<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>

Ogni proprietà Button è Command associata a una proprietà denominata NavigateCommande l'oggetto CommandParameter è impostato su un Type oggetto corrispondente a una delle classi di pagine nel progetto.

Tale NavigateCommand proprietà è di tipo ICommand e viene definita nel file code-behind:

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; }
}

Il costruttore inizializza la NavigateCommand proprietà in un Command<Type> oggetto perché Type è il tipo dell'oggetto CommandParameter impostato nel file XAML. Ciò significa che il execute metodo ha un argomento di tipo Type che corrisponde a questo CommandParameter oggetto. La funzione crea un'istanza della pagina e quindi passa a essa.

Si noti che il costruttore termina impostandolo BindingContext su se stesso. Questa operazione è necessaria per le proprietà nel file XAML da associare alla NavigateCommand proprietà .

Premendo e rilasciando il pulsante

Oltre all'evento Clicked, Button definisce anche gli eventi Pressed e Released. L'evento Pressed si verifica quando un dito preme su un Buttonoggetto o quando viene premuto un pulsante del mouse con il puntatore posizionato su Button. L'evento Released si verifica quando viene rilasciato il dito o il pulsante del mouse. In genere, viene generato anche un Clicked evento contemporaneamente all'evento Released , ma se il puntatore del mouse o il dito si allontana dalla superficie dell'oggetto Button prima del rilascio, l'evento Clicked potrebbe non verificarsi.

Gli Pressed eventi e non vengono spesso usati, ma possono essere usati per scopi speciali, come illustrato nella pagina Press and Release Button .The and Released Release Button are not used, but they can be used for special purposes, as illustrate nella pagina Press and Release Button . Il file XAML contiene un Label oggetto e un Button oggetto con gestori associati per gli Pressed eventi e Released :

<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>

Il file code-behind anima l'oggetto Label quando si verifica un Pressed evento, ma sospende la rotazione quando si verifica un Released evento:

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();
    }
}

Il risultato è che l'unico Label ruota mentre un dito è in contatto con , Buttone si interrompe quando il dito viene rilasciato:

Press and Release Button

Questo tipo di comportamento ha applicazioni per i giochi: un dito tenuto su un Button oggetto potrebbe far muovere un oggetto sullo schermo in una particolare direzione.

Aspetto pulsante

Eredita Button o definisce diverse proprietà che ne influiscono sull'aspetto:

  • TextColor è il colore del Button testo
  • BackgroundColor è il colore dello sfondo del testo
  • BorderColor è il colore di un'area che circonda il Button
  • FontFamily è la famiglia di caratteri utilizzata per il testo
  • FontSize è la dimensione del testo
  • FontAttributes indica se il testo è in corsivo o grassetto
  • BorderWidth è la larghezza del bordo
  • CornerRadius è il raggio dell'angolo del Button
  • CharacterSpacing è la spaziatura tra i caratteri del Button testo.
  • TextTransform determina la combinazione di maiuscole e minuscole del Button testo.

Nota

La Button classe dispone Margin inoltre di proprietà e Padding che controllano il comportamento del layout dell'oggetto Button. Per altre informazioni, vedere l'articolo sulle proprietà Margin e Padding.

Gli effetti di sei di queste proprietà (esclusi FontFamily e FontAttributes) vengono illustrati nella pagina Aspetto pulsante. Un'altra proprietà, Image, è descritta nella sezione Uso delle bitmap con il pulsante .

Tutte le visualizzazioni e i data binding nella pagina Aspetto pulsante sono definiti nel file 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>

Nella Button parte superiore della pagina sono associate tre Color proprietà agli Picker elementi nella parte inferiore della pagina. Gli elementi negli Picker elementi sono colori della NamedColor classe inclusa nel progetto. Tre Slider elementi contengono associazioni bidirezionali alle FontSizeproprietà , BorderWidthe CornerRadius di Button.

Questo programma consente di sperimentare combinazioni di tutte queste proprietà:

Button Appearance

Per visualizzare il Button bordo, è necessario impostare un oggetto su un BorderColor valore diverso da Defaulte su BorderWidth un valore positivo.

In iOS si noterà che le larghezze dei bordi di grandi dimensioni nell'interno dell'oggetto Button e interferiscono con la visualizzazione del testo. Se si sceglie di usare un bordo con un iOS Button, è probabile che si voglia iniziare e terminare la proprietà con spazi per conservarne la Text visibilità.

Nella piattaforma UWP, selezionando un valore CornerRadius che supera la metà dell'altezza di genera un'eccezione Button .

Stati di visualizzazione pulsante

Button dispone di un oggetto PressedVisualState che può essere usato per avviare una modifica visiva a Button quando viene premuto dall'utente, purché sia abilitato.

L'esempio XAML seguente illustra come definire uno stato di visualizzazione per lo Pressed stato:

<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>

Specifica PressedVisualState che, quando Button viene premuto , la relativa Scale proprietà verrà modificata dal valore predefinito da 1 a 0,8. NormalVisualState Specifica che quando l'oggetto Button è in uno stato normale, la relativa Scale proprietà verrà impostata su 1. Di conseguenza, l'effetto complessivo è che, quando Button viene premuto, viene ridimensionato leggermente più piccolo e, quando Button viene rilasciato, viene ridimensionato in base alle dimensioni predefinite.

Per altre informazioni sugli stati di visualizzazione, vedere Xamarin.Forms Visual State Manager.

Creazione di un interruttore

È possibile sottoclasse Button in modo che funzioni come un interruttore on-off: tocca il pulsante una volta per attivare o disattivare il pulsante e toccalo di nuovo per disattivarlo.

La classe seguente deriva da Button e definisce un nuovo evento denominato Toggled e una proprietà booleana denominata IsToggled.ToggleButton Queste sono le stesse due proprietà definite da 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");
    }
}

Il ToggleButton costruttore associa un gestore all'evento Clicked in modo che possa modificare il valore della IsToggled proprietà. Il OnIsToggledChanged metodo genera l'evento Toggled .

L'ultima riga del OnIsToggledChanged metodo chiama il metodo statico VisualStateManager.GoToState con le due stringhe di testo "ToggledOn" e "ToggledOff". È possibile leggere informazioni su questo metodo e su come l'applicazione può rispondere agli stati di visualizzazione nell'articolo Gestione Xamarin.Forms stati di Visual.

Poiché ToggleButton effettua la chiamata a VisualStateManager.GoToState, la classe stessa non deve includere alcuna funzionalità aggiuntiva per modificare l'aspetto del pulsante in base al relativo IsToggled stato. È responsabilità del codice XAML che ospita l'oggetto ToggleButton.

La pagina Demo pulsante attiva/disattiva contiene due istanze di ToggleButton, tra cui il markup di Visual State Manager che imposta , TextBackgroundColore TextColor del pulsante in base allo stato di visualizzazione:

<?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>

I Toggled gestori eventi si trovano nel file code-behind. Sono responsabili dell'impostazione della FontAttributes proprietà dell'oggetto Label in base allo stato dei pulsanti:

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;
        }
    }
}

Ecco il programma in esecuzione in iOS, Android e la piattaforma UWP:

Toggle Button Demo

Uso di bitmap con pulsanti

La Button classe definisce una ImageSource proprietà che consente di visualizzare un'immagine bitmap in Button, da sola o in combinazione con il testo. È anche possibile specificare la disposizione del testo e dell'immagine.

La ImageSource proprietà è di tipo ImageSource, il che significa che le bitmap possono essere caricate da un file, una risorsa incorporata, un URI o un flusso.

Nota

Mentre un Button oggetto può caricare una GIF animata, visualizzerà solo il primo fotogramma della GIF.

Ogni piattaforma supportata da Xamarin.Forms consente di archiviare le immagini in più dimensioni per risoluzioni in pixel diverse dei vari dispositivi su cui l'applicazione potrebbe essere eseguita. Queste bitmap multiple sono denominate o archiviate in modo che il sistema operativo possa scegliere la corrispondenza migliore per la risoluzione di visualizzazione video del dispositivo.

Per una bitmap in un Buttonoggetto , le dimensioni migliori sono in genere comprese tra 32 e 64 unità indipendenti dal dispositivo, a seconda della dimensione desiderata. Le immagini usate in questo esempio si basano su una dimensione di 48 unità indipendenti dal dispositivo.

Nel progetto iOS la cartella Resources contiene tre dimensioni di questa immagine:

  • Bitmap quadrata a 48 pixel archiviata come /Resources/MonkeyFace.png
  • Bitmap quadrata a 96 pixel archiviata come /Resource/MonkeyFace@2x.png
  • Bitmap quadrata a 144 pixel archiviata come /Resource/MonkeyFace@3x.png

A tutte e tre le bitmap è stata assegnata un'azione di compilazione bundleResource.

Per il progetto Android, le bitmap hanno lo stesso nome, ma vengono archiviate in sottocartelle diverse della cartella Resources :

  • Bitmap quadrata a 72 pixel archiviata come /Resources/drawable-hdpi/MonkeyFace.png
  • Bitmap quadrata a 96 pixel archiviata come /Resources/drawable-xhdpi/MonkeyFace.png
  • Bitmap quadrata a 144 pixel archiviata come /Resources/drawable-xxhdpi/MonkeyFace.png
  • Bitmap quadrata a 192 pixel archiviata come /Resources/drawable-xxxhdpi/MonkeyFace.png

A questi dati è stata assegnata un'azione di compilazione di AndroidResource.

Nel progetto UWP le bitmap possono essere archiviate in qualsiasi punto del progetto, ma in genere vengono archiviate in una cartella personalizzata o nella cartella Assets esistente. Il progetto UWP contiene queste bitmap:

  • Bitmap quadrata a 48 pixel archiviata come /Assets/MonkeyFace.scale-100.png
  • Bitmap quadrata a 96 pixel archiviata come /Assets/MonkeyFace.scale-200.png
  • Bitmap quadrata a 192 pixel archiviata come /Assets/MonkeyFace.scale-400.png

Tutti hanno ricevuto un'azione di compilazione del contenuto.

È possibile specificare la modalità di disposizione delle proprietà e ImageSource nell'oggetto Button utilizzando la ContentLayout proprietà di Button.Text Questa proprietà è di tipo ButtonContentLayout, che è una classe incorporata in Button. Il costruttore ha due argomenti:

  • Membro dell'enumerazione ImagePosition : Left, Top, Righto Bottom che indica la modalità di visualizzazione della bitmap rispetto al testo.
  • Valore double per la spaziatura tra la bitmap e il testo.

Le impostazioni predefinite sono Left e 10 unità. Due proprietà di sola lettura di ButtonContentLayout denominate Position e Spacing forniscono i valori di tali proprietà.

Nel codice è possibile creare e Button impostare la ContentLayout proprietà come segue:

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

In XAML è necessario specificare solo il membro di enumerazione o la spaziatura o entrambi in qualsiasi ordine separato da virgole:

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

La pagina Demo pulsante immagine usa OnPlatform per specificare nomi di file diversi per i file bitmap iOS, Android e UWP. Se vuoi usare lo stesso nome file per ogni piattaforma ed evitare l'uso di OnPlatform, dovrai archiviare le bitmap UWP nella directory radice del progetto.

La prima Button nella pagina Demo pulsante immagine imposta la Image proprietà ma non la Text proprietà :

<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>

Se le bitmap UWP vengono archiviate nella directory radice del progetto, questo markup può essere notevolmente semplificato:

<Button ImageSource="MonkeyFace.png" />

Per evitare un sacco di markup ripetitivo nel file ImageButtonDemo.xaml , viene definito anche un implicito Style per impostare la ImageSource proprietà. Questa operazione Style viene applicata automaticamente a cinque altri Button elementi. Ecco il file XAML completo:

<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>

I quattro Button elementi finali usano la ContentLayout proprietà per specificare una posizione e una spaziatura del testo e della bitmap:

Image Button Demo

Sono stati ora illustrati i vari modi in cui è possibile gestire Button gli eventi e modificare l'aspetto Button .