Comportamentos

Browse sample. Navegue pelo exemplo

Os comportamentos da IU do aplicativo multiplataforma do .NET (.NET MAUI) permitem adicionar funcionalidade aos controles da interface do usuário sem precisar subclassificá-los. Em vez disso, a funcionalidade é implementada em uma classe de comportamento e anexada ao controle como se fizesse parte do próprio controle.

Os comportamentos permitem que você implemente código que normalmente precisaria escrever como code-behind, porque interagem diretamente com a API do controle, de forma que podem ser anexados de forma concisa ao controle e empacotados para reutilização em mais de um aplicativo. Eles podem ser usados para fornecer uma ampla gama de funcionalidade para controles, como:

  • Adicionar um validador de email a um Entry.
  • Criar um controle de classificação usando um reconhecedor de gesto de toque.
  • Controlar uma animação.

O .NET MAUI oferece suporte a três tipos diferentes de comportamentos:

  • Comportamentos anexados são classes static com uma ou mais propriedades anexadas. Para obter mais informações sobre comportamentos anexados, consulte Comportamentos anexados.
  • Comportamentos MAUI do .NET são classes que derivam da Behavior classe ou Behavior<T> , onde T é o tipo do controle ao qual o comportamento deve se aplicar. Para obter mais informações, consulte Comportamentos do .NET MAUI.
  • Os comportamentos de plataforma são classes derivadas da PlatformBehavior<TView> classe ou PlatformBehavior<TView,TPlatformView> . Esses comportamentos podem responder a condições e eventos arbitrários em um controle nativo. Para obter mais informações, consulte Comportamentos de plataforma.

Comportamentos anexados

Comportamentos anexados são classes estáticas com uma ou mais propriedades anexadas. Uma propriedade anexada é um tipo especial de propriedade associável. Elas são definidas em uma classe, mas são anexadas a outros objetos e reconhecíveis no XAML como atributos que contêm uma classe e um nome de propriedade separados por um ponto. Para obter mais informações sobre propriedades anexadas, consulte Propriedades anexadas.

Uma propriedade anexada pode definir um delegado propertyChanged que será executado quando o valor da propriedade for alterado, por exemplo, quando a propriedade for definida em um controle. Quando o delegado propertyChanged é executado, é passada a ele uma referência ao controle a que ele está sendo anexado, bem como parâmetros que contêm os valores antigo e novo da propriedade. Esse delegado pode ser usado para adicionar uma nova funcionalidade ao controle a que a propriedade está anexada manipulando a referência que é passada, da seguinte maneira:

  1. O delegado propertyChanged converte a referência do controle, que é recebida como um BindableObject, para o tipo de comportamento que o controle deve melhorar.
  2. O delegado propertyChanged modifica as propriedades do controle, chama os métodos do controle ou registra manipuladores de eventos para eventos expostos pelo controle, a fim de implementar a funcionalidade do comportamento de núcleo.

Aviso

Os comportamentos anexados são definidos em uma static classe, com static propriedades e métodos. Isso dificulta a criação de comportamentos anexados com estado.

Criar um comportamento anexado

Um comportamento anexado pode ser implementado criando uma classe estática que contém uma propriedade anexada que especifica um propertyChanged delegado.

O exemplo a seguir mostra a AttachedNumericValidationBehavior classe, que destaca o valor inserido pelo usuário em um controle em vermelho se não for um Entrydouble:

public static class AttachedNumericValidationBehavior
{
    public static readonly BindableProperty AttachBehaviorProperty =
        BindableProperty.CreateAttached("AttachBehavior", typeof(bool), typeof(AttachedNumericValidationBehavior), false, propertyChanged: OnAttachBehaviorChanged);

    public static bool GetAttachBehavior(BindableObject view)
    {
        return (bool)view.GetValue(AttachBehaviorProperty);
    }

    public static void SetAttachBehavior(BindableObject view, bool value)
    {
        view.SetValue(AttachBehaviorProperty, value);
    }

    static void OnAttachBehaviorChanged(BindableObject view, object oldValue, object newValue)
    {
        Entry entry = view as Entry;
        if (entry == null)
        {
            return;
        }

        bool attachBehavior = (bool)newValue;
        if (attachBehavior)
        {
            entry.TextChanged += OnEntryTextChanged;
        }
        else
        {
            entry.TextChanged -= OnEntryTextChanged;
        }
    }

    static void OnEntryTextChanged(object sender, TextChangedEventArgs args)
    {
        double result;
        bool isValid = double.TryParse(args.NewTextValue, out result);
        ((Entry)sender).TextColor = isValid ? Colors.Black : Colors.Red;
    }
}

Neste exemplo, a classe contém uma propriedade anexada nomeada AttachBehavior com um static getter e setter, que controla a AttachedNumericValidationBehavior adição ou remoção do comportamento ao controle ao qual ele será anexado. Essa propriedade anexada registra o método OnAttachBehaviorChanged que será executado quando o valor da propriedade for alterado. Esse método registra ou cancela o registra de um manipulador de eventos para o evento TextChanged, com base no valor da propriedade anexada AttachBehavior. A funcionalidade principal do comportamento é fornecida pelo OnEntryTextChanged método, que analisa o valor inserido no Entry e define a TextColor propriedade como vermelho se o valor não for um double.

Consumir um comportamento anexado

Um comportamento anexado pode ser consumido definindo sua propriedade anexada no controle de destino.

O exemplo a seguir mostra o consumo da AttachedNumericValidationBehavior classe em um Entry adicionando a propriedade anexada AttachBehaviorEntryao :


<ContentPage ...
             xmlns:local="clr-namespace:BehaviorsDemos">
    <Entry Placeholder="Enter a System.Double" local:AttachedNumericValidationBehavior.AttachBehavior="true" />
</ContentPage>

O Entry equivalente em C# é mostrado no exemplo de código a seguir:

Entry entry = new Entry { Placeholder = "Enter a System.Double" };
AttachedNumericValidationBehavior.SetAttachBehavior(entry, true);

A captura de tela a seguir mostra o comportamento anexado respondendo a entrada inválida:

Screenshot of attached behavior responding to invalid input

Observação

Comportamentos anexados são escritos para um tipo de controle específico (ou uma superclasse que pode ser aplicada a muitos controles) e só devem ser adicionados a um controle compatível.

Remover um comportamento anexado

A AttachedNumericValidationBehavior classe pode ser removida de um controle definindo a propriedade anexada AttachBehavior como false:

<Entry Placeholder="Enter a System.Double" local:AttachedNumericValidationBehavior.AttachBehavior="false" />

No runtime, o método OnAttachBehaviorChanged será executado quando o valor da propriedade anexada AttachBehavior for definida como false. O OnAttachBehaviorChanged método cancelará o registro do manipulador de eventos para o evento, garantindo que o comportamento não seja executado à medida que você interage com o TextChanged controle.

Comportamentos do .NET MAUI

Os comportamentos do .NET MAUI são criados derivando da Behavior classe ou Behavior<T> .

O processo para criar um comportamento MAUI do .NET é o seguinte:

  1. Criar uma classe que herda da classe Behavior ou Behavior<T>, em que T é o tipo do controle ao qual o comportamento deve ser aplicado.
  2. Substituir o método OnAttachedTo para executar qualquer configuração necessária.
  3. Substituir o método OnDetachingFrom para executar qualquer limpeza necessária.
  4. Implementar a funcionalidade principal do comportamento.

Isso resulta na estrutura mostrada no exemplo a seguir:

public class MyBehavior : Behavior<View>
{
    protected override void OnAttachedTo(View bindable)
    {
        base.OnAttachedTo(bindable);
        // Perform setup
    }

    protected override void OnDetachingFrom(View bindable)
    {
        base.OnDetachingFrom(bindable);
        // Perform clean up
    }

    // Behavior implementation
}

O OnAttachedTo método é chamado imediatamente após o comportamento é anexado a um controle. Esse método recebe uma referência ao controle ao qual ele está anexado e pode ser usado para registrar manipuladores de eventos ou para realizar outra configuração necessária para dar suporte à funcionalidade do comportamento. Por exemplo, você pode assinar um evento em um controle. A funcionalidade do comportamento, então, seria implementada no manipulador do evento.

O OnDetachingFrom método é chamado quando o comportamento é removido do controle. Esse método recebe uma referência ao controle ao qual ele está anexado e é usado para executar qualquer limpeza necessária. Por exemplo, você poderia cancelar a assinatura de um evento em um controle para evitar perdas de memória.

O comportamento pode então ser consumido anexando-o Behaviors à coleção do controle.

Criar um comportamento MAUI do .NET

Um comportamento .NET Maui pode ser implementado criando uma classe que deriva da classe or e substituindo os BehaviorOnAttachedTo métodos eOnDetachingFrom.Behavior<T>

O exemplo a seguir mostra a NumericValidationBehavior classe, que destaca o valor inserido pelo usuário em um controle em vermelho se não for um Entrydouble:

public class NumericValidationBehavior : Behavior<Entry>
{
    protected override void OnAttachedTo(Entry entry)
    {
        entry.TextChanged += OnEntryTextChanged;
        base.OnAttachedTo(entry);
    }

    protected override void OnDetachingFrom(Entry entry)
    {
        entry.TextChanged -= OnEntryTextChanged;
        base.OnDetachingFrom(entry);
    }

    void OnEntryTextChanged(object sender, TextChangedEventArgs args)
    {
        double result;
        bool isValid = double.TryParse(args.NewTextValue, out result);
        ((Entry)sender).TextColor = isValid ? Colors.Black : Colors.Red;
    }
}

Neste exemplo, a NumericValidationBehavior classe deriva da Behavior<T> classe, onde T é um Entryarquivo . O método OnAttachedTo registra um manipulador de eventos para o evento TextChanged, com o método OnDetachingFrom cancelando o registro do evento TextChanged para evitar perdas de memória. A funcionalidade principal do comportamento é fornecida pelo OnEntryTextChanged método, que analisa o valor inserido no Entry e define a TextColor propriedade como vermelho se o valor não for um double.

Importante

O .NET MAUI não define o de um comportamento, porque os BindingContext comportamentos podem ser compartilhados e aplicados a vários controles por meio de estilos.

Consumir um comportamento MAUI do .NET

Cada controle MAUI do .NET tem uma Behaviors coleção, à qual um ou mais comportamentos podem ser adicionados:

<Entry Placeholder="Enter a System.Double">
    <Entry.Behaviors>
        <local:NumericValidationBehavior />
    </Entry.Behaviors>
</Entry>

O Entry equivalente em C# é mostrado no exemplo de código a seguir:

Entry entry = new Entry { Placeholder = "Enter a System.Double" };
entry.Behaviors.Add(new NumericValidationBehavior());

A captura de tela a seguir mostra o comportamento do .NET MAUI respondendo a entrada inválida:

Screenshot of .NET MAUI behavior responding to invalid input

Aviso

Os comportamentos MAUI do .NET são escritos para um tipo de controle específico (ou uma superclasse que pode se aplicar a muitos controles) e só devem ser adicionados a um controle compatível. A tentativa de anexar um comportamento MAUI do .NET a um controle incompatível resultará em uma exceção sendo lançada.

Consumir um comportamento MAUI do .NET com um estilo

Os comportamentos do .NET MAUI podem ser consumidos por um estilo explícito ou implícito. No entanto, não é possível criar um estilo que define a propriedade Behaviors de um controle porque a propriedade é somente leitura. A solução é adicionar uma propriedade anexada à classe do comportamento que controla a adição e a remoção do comportamento. O processo é o seguinte:

  1. Adicione uma propriedade anexada à classe de comportamento que será usada para controlar a adição ou remoção do comportamento ao controle ao qual o comportamento será anexado. Certifique-se de que a propriedade anexada registre um delegado propertyChanged que será executado quando o valor da propriedade for alterado.
  2. Crie um getter e setter static para a propriedade anexada.
  3. Implemente a lógica no delegado propertyChanged para adicionar e remover o comportamento.

O exemplo a seguir mostra a NumericValidationStyleBehavior classe, que tem uma propriedade anexada que controla a adição e remoção do comportamento:

public class NumericValidationStyleBehavior : Behavior<Entry>
{
    public static readonly BindableProperty AttachBehaviorProperty =
        BindableProperty.CreateAttached("AttachBehavior", typeof(bool), typeof(NumericValidationStyleBehavior), false, propertyChanged: OnAttachBehaviorChanged);

    public static bool GetAttachBehavior(BindableObject view)
    {
        return (bool)view.GetValue(AttachBehaviorProperty);
    }

    public static void SetAttachBehavior(BindableObject view, bool value)
    {
        view.SetValue(AttachBehaviorProperty, value);
    }

    static void OnAttachBehaviorChanged(BindableObject view, object oldValue, object newValue)
    {
        Entry entry = view as Entry;
        if (entry == null)
        {
            return;
        }

        bool attachBehavior = (bool)newValue;
        if (attachBehavior)
        {
            entry.Behaviors.Add(new NumericValidationStyleBehavior());
        }
        else
        {
            Behavior toRemove = entry.Behaviors.FirstOrDefault(b => b is NumericValidationStyleBehavior);
            if (toRemove != null)
            {
                entry.Behaviors.Remove(toRemove);
            }
        }
    }

    protected override void OnAttachedTo(Entry entry)
    {
        entry.TextChanged += OnEntryTextChanged;
        base.OnAttachedTo(entry);
    }

    protected override void OnDetachingFrom(Entry entry)
    {
        entry.TextChanged -= OnEntryTextChanged;
        base.OnDetachingFrom(entry);
    }

    void OnEntryTextChanged(object sender, TextChangedEventArgs args)
    {
        double result;
        bool isValid = double.TryParse(args.NewTextValue, out result);
        ((Entry)sender).TextColor = isValid ? Colors.Black : Colors.Red;
    }
}

Neste exemplo, a classe contém uma propriedade anexada nomeada AttachBehavior com um static getter e setter, que controla a NumericValidationStyleBehavior adição ou remoção do comportamento ao controle ao qual ele será anexado. Essa propriedade anexada registra o método OnAttachBehaviorChanged que será executado quando o valor da propriedade for alterado. Esse método adiciona ou remove o comportamento do controle com base no valor da propriedade anexada AttachBehavior.

O seguinte exemplo de código mostra um estilo explícito para o NumericValidationStyleBehavior que usa a propriedade anexada AttachBehavior e que pode ser aplicado a controles Entry:

<Style x:Key="NumericValidationStyle" TargetType="Entry">
    <Style.Setters>
        <Setter Property="local:NumericValidationStyleBehavior.AttachBehavior" Value="true" />
    </Style.Setters>
</Style>

O Style pode ser aplicado a um Entry definindo sua Style propriedade para o estilo usando a extensão de StaticResource marcação:

<Entry Placeholder="Enter a System.Double" Style="{StaticResource NumericValidationStyle}">

Para mais informações sobre estilos, confira Estilos.

Observação

Embora seja possível adicionar propriedades vinculáveis a um comportamento definido ou consultado no XAML, se você criar comportamentos com estado, eles não deverão ser compartilhados entre os controles em um Style em um ResourceDictionary.

Remover um comportamento MAUI do .NET

O OnDetachingFrom método é chamado quando um comportamento é removido de um controle e é usado para executar qualquer limpeza necessária, como cancelar a assinatura de um evento para evitar um vazamento de memória. No entanto, os comportamentos não são removidos implicitamente dos controles, a menos que a coleção do Behaviors controle seja modificada pelo Remove método ou Clear :

Behavior toRemove = entry.Behaviors.FirstOrDefault(b => b is NumericValidationStyleBehavior);
if (toRemove != null)
{
    entry.Behaviors.Remove(toRemove);
}

Como alternativa, a coleta do Behaviors controle pode ser limpa:

entry.Behaviors.Clear();

Observação

Os comportamentos do .NET MAUI não são removidos implicitamente dos controles quando as páginas são exibidas da pilha de navegação. Em vez disso, eles devem ser removidos explicitamente antes que páginas saiam do escopo.

Comportamentos da plataforma

Os comportamentos da plataforma são criados derivando da PlatformBehavior<TView> classe ou PlatformBehavior<TView,TPlatformView> . Eles respondem a condições e eventos arbitrários em um controle nativo.

Um comportamento de plataforma pode ser implementado por meio de compilação condicional ou classes parciais. A abordagem adotada aqui é usar classes parciais, onde um comportamento de plataforma normalmente consiste em uma classe parcial de plataforma cruzada que define a API de comportamentos e uma classe parcial nativa que implementa o comportamento em cada plataforma. Em tempo de compilação, a multisegmentação combina as classes parciais para criar o comportamento da plataforma em cada plataforma.

O processo para criar um comportamento de plataforma é o seguinte:

  1. Crie uma classe parcial entre plataformas que defina a API para o comportamento da plataforma.

  2. Crie uma classe parcial nativa em cada plataforma para a qual seu aplicativo foi criado, que tenha o mesmo nome da classe parcial entre plataformas. Essa classe parcial nativa deve herdar da PlatformBehavior<TView> classe ou PlatformBehavior<TView,TPlatformView> , onde TView é o controle entre plataformas ao qual o comportamento deve se aplicar e TPlatformView é a exibição nativa que implementa o controle entre plataformas em uma plataforma específica.

    Observação

    Embora seja necessário criar uma classe parcial nativa em cada plataforma para a qual seu aplicativo foi criado, não é necessário implementar a funcionalidade de comportamento da plataforma em todas as plataformas. Por exemplo, você pode criar um comportamento de plataforma que modifique a espessura da borda de um controle nativo em algumas, mas não em todas, plataformas.

  3. Em cada classe parcial nativa necessária para implementar o comportamento da plataforma, você deve:

    1. Substitua o OnAttachedTo método para executar qualquer configuração.
    2. Substitua o OnDetachedFrom método para executar qualquer limpeza.
    3. Implemente a funcionalidade principal do comportamento da plataforma.

O comportamento pode então ser consumido anexando-o Behaviors à coleção do controle.

Criar um comportamento de plataforma

Para criar um comportamento de plataforma, você deve primeiro criar uma classe parcial de plataforma cruzada que defina a API para o comportamento da plataforma:

namespace BehaviorsDemos
{
    public partial class TintColorBehavior
    {
        public static readonly BindableProperty TintColorProperty =
            BindableProperty.Create(nameof(TintColor), typeof(Color), typeof(TintColorBehavior));

        public Color TintColor
        {
            get => (Color)GetValue(TintColorProperty);
            set => SetValue(TintColorProperty, value);
        }
    }
}

O comportamento da plataforma é uma classe parcial cuja implementação será concluída em cada plataforma necessária com uma classe parcial adicional que usa o mesmo nome. Neste exemplo, a classe define uma única propriedade vinculável, , TintColorque matizará uma imagem com a TintColorBehavior cor especificada.

Depois de criar a classe parcial de plataforma cruzada, você deve criar uma classe parcial nativa em cada plataforma para a qual você cria o aplicativo. Isso pode ser feito adicionando classes parciais às pastas filhas necessárias da pasta Plataformas :

Screenshot of the native partial classes for a platform behavior.

Como alternativa, você pode configurar seu projeto para oferecer suporte a multidirecionamento baseado em nome de arquivo, multidirecionamento baseado em pasta ou ambos. Para obter mais informações sobre multisegmentação, consulte Configurar multisegmentação.

As classes parciais nativas devem herdar da PlatformBehavior<TView> classe ou da PlatformBehavior<TView,TPlatformView> classe, onde TView é o controle entre plataformas ao qual o comportamento deve se aplicar e TPlatformView é a exibição nativa que implementa o controle entre plataformas em uma plataforma específica. Em cada classe parcial nativa necessária para implementar o comportamento da plataforma, você deve substituir o método e o OnAttachedToOnDetachedFrom método e implementar a funcionalidade principal do comportamento da plataforma.

O OnAttachedTo método é chamado imediatamente após o comportamento da plataforma ser anexado a um controle de plataforma cruzada. O método recebe uma referência ao controle de plataforma cruzada ao qual ele está anexado e, opcionalmente, uma referência ao controle nativo que implementa o controle de plataforma cruzada. O método pode ser usado para registrar manipuladores de eventos ou executar outra configuração necessária para oferecer suporte à funcionalidade de comportamento da plataforma. Por exemplo, você pode assinar um evento em um controle. A funcionalidade do comportamento, então, seria implementada no manipulador do evento.

O OnDetachedFrom método é chamado quando o comportamento é removido do controle de plataforma cruzada. O método recebe uma referência ao controle ao qual ele está anexado e, opcionalmente, uma referência ao controle nativo que implementa o controle entre plataformas. O método deve ser usado para executar qualquer limpeza necessária. Por exemplo, você poderia cancelar a assinatura de um evento em um controle para evitar perdas de memória.

Importante

As classes parciais devem residir no mesmo namespace e usar nomes idênticos.

O exemplo a seguir mostra a TintColorBehavior classe parcial para Android, que matiza uma imagem com uma cor especificada:

using Android.Graphics;
using Android.Widget;
using Microsoft.Maui.Platform;
using Color = Microsoft.Maui.Graphics.Color;

namespace BehaviorsDemos
{
    public partial class TintColorBehavior : PlatformBehavior<Image, ImageView>
    {
        protected override void OnAttachedTo(Image bindable, ImageView platformView)
        {
            base.OnAttachedTo(bindable, platformView);

            if (bindable is null)
                return;
            if (TintColor is null)
                ClearColor(platformView);
            else
                ApplyColor(platformView, TintColor);
        }

        protected override void OnDetachedFrom(Image bindable, ImageView platformView)
        {
            base.OnDetachedFrom(bindable, platformView);

            if (bindable is null)
                return;
            ClearColor(platformView);
        }

        void ApplyColor(ImageView imageView, Color color)
        {
            imageView.SetColorFilter(new PorterDuffColorFilter(color.ToPlatform(), PorterDuff.Mode.SrcIn ?? throw new NullReferenceException()));
        }

        void ClearColor(ImageView imageView)
        {
            imageView.ClearColorFilter();
        }
    }
}

Neste exemplo, a TintColorBehavior classe deriva da PlatformBehavior<TView,TPlatformView> classe, onde TView é um e TPlatformView é um ImageImageView. O OnAttachedTo aplica a cor de tonalidade à imagem, desde que a TintColor propriedade tenha um valor. O OnDetachedFrom método remove a cor da tonalidade da imagem.

Uma classe parcial nativa deve ser adicionada em cada plataforma para a qual você cria seu aplicativo. No entanto, você pode fazer a classe parcial nativa NO-OP, se o comportamento da plataforma não for necessário em uma plataforma específica. Isso pode ser alcançado fornecendo uma classe vazia:

using Microsoft.UI.Xaml;

namespace BehaviorsDemos
{
    public partial class TintColorBehavior : PlatformBehavior<Image, FrameworkElement>
    {
        // NO-OP on Windows
    }
}

Importante

O .NET MAUI não define o BindingContext comportamento de uma plataforma.

Consumir um comportamento de plataforma

Cada controle .NET MAUI tem uma Behaviors coleção, à qual um ou mais comportamentos de plataforma podem ser adicionados:

<Image Source="dotnet_bot.png"
       HeightRequest="200"
       HorizontalOptions="Center">
    <Image.Behaviors>
        <local:TintColorBehavior TintColor="Red" />
    </Image.Behaviors>
</Image>

O equivalente Image em C# é mostrado no exemplo a seguir:

Image image = new Image { Source = "dotnet_bot.png", HeightRequest = 200, HorizontalOptions = LayoutOptions.Center };
image.Behaviors.Add(new TintColorBehavior());

A captura de tela a seguir mostra o comportamento da plataforma matizando uma imagem:

Screenshot of .NET MAUI platform behavior tinting an image.

Aviso

Os comportamentos de plataforma são escritos para um tipo de controle específico (ou uma superclasse que pode se aplicar a muitos controles) e só devem ser adicionados a um controle compatível. A tentativa de anexar um comportamento de plataforma a um controle incompatível resultará em uma exceção sendo lançada.