Comportamentos
Os comportamentos do .NET MAUI para interfaces de usuário multiplataforma permitem adicionar funcionalidades extras aos controles de interface do usuário, como Button ou Entry, sem precisar subclassificar os controles. Em vez disso, a funcionalidade extra é implementada em uma classe Behavior e anexada ao controle.
Comportamentos podem ser usados para adicionar funcionalidades diferentes aos controles de interface do usuário, como:
- Validações de entrada. Comportamentos podem ser usados com controles de entrada para garantir que os dados sejam válidos. Por exemplo, você pode escrever um comportamento para um Entry para garantir que um endereço de email ou número de telefone esteja no formato correto.
- Aprimorando a interface do usuário. Comportamentos podem ser usados para aprimorar os controles de interface do usuário em seu aplicativo. Por exemplo, você pode escrever um comportamento para um Button fazer com que ele trema quando ele é clicado ou alterar a cor.
- Respostas de runtime. Comportamentos podem ser usados para fazer os controles reagirem a situações diferentes. Por exemplo, você pode salvar automaticamente a entrada do usuário em um Entry quando um usuário terminar de digitar.
O MAUI do .NET dá suporte a três tipos diferentes de comportamentos:
- Comportamentos anexados são classes
static
com uma ou mais propriedades vinculadas. Para obter mais informações sobre comportamentos anexados, consulte Comportamentos anexados. - Os comportamentos do .NET MAUI são classes que derivam da classe Behavior ou Behavior<T>, em que
T
é o tipo do controle ao qual o comportamento deve ser aplicado. Para obter mais informações, consulte Behaviors do .NET MAUI. - Comportamentos de plataforma são classes que derivam da classe PlatformBehavior<TView> ou PlatformBehavior<TView,TPlatformView>. Esses comportamentos podem responder a condições arbitrárias e eventos em um controle nativo. Para mais informações, veja Comportamentos da Plataforma.
Comportamentos anexados
Comportamentos anexados são classes estáticas com uma ou mais propriedades anexadas. Uma propriedade anexada é um tipo especial de propriedade vinculável. Eles são definidos em uma classe, mas anexados a outros objetos, e são reconhecíveis em XAML como atributos que contêm uma classe e um nome de propriedade separados por um período. 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, como quando a propriedade é configurada em um controle. Quando o delegado propertyChanged
é executado, uma referência ao controle no qual ele está sendo anexado é passada, junto com parâmetros que contêm os valores antigos e novos para a propriedade. Esse delegado pode ser usado para adicionar novas funcionalidades ao controle ao qual a propriedade está anexada manipulando a referência passada, da seguinte maneira:
- O delegado
propertyChanged
faz a conversão da referência de controle, que é recebida como um BindableObject, para o tipo de controle que o comportamento foi projetado para aprimorar. - O delegado
propertyChanged
modifica propriedades do controle, chama métodos do controle ou registra manipuladores de eventos para eventos expostos pelo controle, para implementar a funcionalidade de comportamento principal.
Aviso
Comportamentos anexados são definidos em uma classe static
, com propriedades e métodos static
. Isso dificulta a criação de comportamentos acoplados que mantêm estado.
Criar um comportamento associado
Um comportamento anexado pode ser implementado criando uma classe estática que contém uma propriedade anexada que especifica um delegado propertyChanged
.
O exemplo a seguir mostra a classe AttachedNumericValidationBehavior
, que realça o valor inserido pelo usuário em um controle Entry em vermelho se não for um double
:
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 AttachedNumericValidationBehavior
contém uma propriedade anexada chamada AttachBehavior
com um static
getter e setter, que controla a 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 anula o registro de um manipulador de eventos para o evento TextChanged
, com base no valor da propriedade anexada AttachBehavior
. A funcionalidade principal do comportamento é fornecida pelo método OnEntryTextChanged
, que analisa o valor inserido no Entry e define a propriedade TextColor
como vermelha se o valor não for um double
.
Utilizar 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 classe AttachedNumericValidationBehavior
em um Entry ao adicionar a propriedade associada AttachBehavior
ao Entry:
<ContentPage ...
xmlns:local="clr-namespace:BehaviorsDemos">
<Entry Placeholder="Enter a System.Double" local:AttachedNumericValidationBehavior.AttachBehavior="true" />
</ContentPage>
O Entry equivalente em C# é mostrado no seguinte exemplo de código:
Entry entry = new Entry { Placeholder = "Enter a System.Double" };
AttachedNumericValidationBehavior.SetAttachBehavior(entry, true);
A captura de tela a seguir mostra o comportamento anexado respondendo à entrada inválida:
Nota
Comportamentos anexados são gravados para um tipo de controle específico (ou uma superclasse que pode se aplicar a muitos controles) e eles só devem ser adicionados a um controle compatível.
Remover um comportamento anexado
A classe AttachedNumericValidationBehavior
pode ser removida de um controle definindo a propriedade anexada AttachBehavior
como false
:
<Entry Placeholder="Enter a System.Double" local:AttachedNumericValidationBehavior.AttachBehavior="false" />
Em runtime, o método OnAttachBehaviorChanged
será executado quando o valor da propriedade anexada AttachBehavior
estiver definido como false
. O método OnAttachBehaviorChanged
desativará o manipulador de eventos do evento TextChanged
, garantindo que o comportamento não seja executado à medida que você interage com o controle.
Comportamentos do .NET MAUI
Os comportamentos do .NET MAUI são criados derivando da classe Behavior ou Behavior<T>.
O processo para criar um comportamento do .NET MAUI é o seguinte:
- Crie uma classe que herda da classe Behavior ou Behavior<T>, em que
T
é o tipo do controle ao qual o comportamento deve ser aplicado. - Substitua o método OnAttachedTo para executar qualquer configuração necessária.
- Substitua o método OnDetachingFrom para executar qualquer limpeza necessária.
- Implemente 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 método OnAttachedTo é chamado imediatamente após o comportamento ser anexado a um controle. Esse método recebe uma referência ao controle ao qual está anexado e pode ser usado para registrar manipuladores de eventos ou executar outra configuração necessária para dar suporte à funcionalidade de comportamento. Por exemplo, você pode assinar um evento em um controle. A funcionalidade de comportamento seria então implementada no manipulador de eventos do evento.
O método OnDetachingFrom é chamado quando o comportamento é removido do controle. Esse método recebe uma referência ao controle ao qual está anexado e é usado para executar qualquer limpeza necessária. Por exemplo, você pode cancelar a assinatura de um evento em um controle para evitar vazamentos de memória.
O comportamento pode ser consumido anexando-o à coleção Behaviors do controle.
Criar um Comportamento .NET MAUI
Um comportamento maui do .NET pode ser implementado criando uma classe que deriva da classe Behavior ou Behavior<T> e substituindo os métodos OnAttachedTo e OnDetachingFrom.
O exemplo a seguir mostra a classe NumericValidationBehavior
, que realça o valor inserido pelo usuário em um controle Entry em vermelho se não for um double
:
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 classe NumericValidationBehavior
deriva da classe Behavior<T>, em que T
é um Entry. O método OnAttachedTo registra um manipulador de eventos para o evento TextChanged
, e o método OnDetachingFrom desregistra o manipulador do evento TextChanged
para evitar vazamentos de memória. A funcionalidade principal do comportamento é fornecida pelo método OnEntryTextChanged
, que analisa o valor inserido no Entry e define a propriedade TextColor
como vermelha se o valor não for um double
.
Importante
O .NET MAUI não define o BindingContext
de um comportamento, pois os comportamentos podem ser compartilhados e aplicados a vários controles por meio de estilos.
Consumir um comportamento .NET MAUI
Cada controle MAUI do .NET tem uma coleção Behaviors, à 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 seguinte exemplo de código:
Entry entry = new Entry { Placeholder = "Enter a System.Double" };
entry.Behaviors.Add(new NumericValidationBehavior());
A captura de tela a seguir mostra o comportamento do MAUI do .NET respondendo à entrada inválida:
Aviso
Os comportamentos MAUI do .NET são gravados para um tipo específico de controle (ou uma superclasse que pode se aplicar a muitos controles) e eles só devem ser adicionados a um controle compatível. A tentativa de anexar um comportamento maui do .NET a um controle incompatível resultará na geração de uma exceção.
Consumir um comportamento .NET MAUI com um estilo
Os comportamentos do .NET MAUI podem ser consumidos por um estilo explícito ou implícito. No entanto, a criação de um estilo que define a propriedade Behaviors de um controle não é possível porque a propriedade é somente leitura. A solução é adicionar uma propriedade anexada à classe de comportamento que controla a adição e remoção do comportamento. O processo é o seguinte:
- 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. Verifique se a propriedade anexada registra um delegado
propertyChanged
que será executado quando o valor da propriedade for alterado. - Crie um
static
getter e setter para a propriedade anexada. - Implemente a lógica no delegado
propertyChanged
para adicionar e remover o comportamento.
O exemplo a seguir mostra a classe NumericValidationStyleBehavior
, 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 NumericValidationStyleBehavior
contém uma propriedade anexada chamada AttachBehavior
com um static
getter e setter, que controla a 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 ao controle, com base no valor da propriedade anexada AttachBehavior
.
O exemplo de código a seguir mostra um estilo explícito
<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 propriedade Style ao estilo usando a extensão de marcação StaticResource
:
<Entry Placeholder="Enter a System.Double" Style="{StaticResource NumericValidationStyle}">
Para obter mais informações sobre estilos, consulte.
Nota
Embora você possa adicionar propriedades associáveis a um comportamento definido ou consultado em XAML, se você criar comportamentos com estado, esses comportamentos não devem ser compartilhados entre controles em um Style dentro de um ResourceDictionary.
Remover um comportamento do .NET MAUI
O método OnDetachingFrom é chamado quando um comportamento é removido de um controle e é usado para executar qualquer limpeza necessária, como cancelar a gravação 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 Behaviors do controle seja modificada pelo método Remove
ou Clear
:
Behavior toRemove = entry.Behaviors.FirstOrDefault(b => b is NumericValidationStyleBehavior);
if (toRemove != null)
{
entry.Behaviors.Remove(toRemove);
}
Como alternativa, a coleção Behaviors do controle pode ser limpada:
entry.Behaviors.Clear();
Nota
Os comportamentos do .NET MAUI não são removidos implicitamente dos controles quando as páginas são retiradas da pilha de navegação. Em vez disso, eles devem ser explicitamente removidos antes que as páginas saiam do escopo.
Comportamentos de plataforma
Os comportamentos da plataforma são criados derivando da classe PlatformBehavior<TView> ou PlatformBehavior<TView,TPlatformView>. Eles respondem a condições arbitrárias e eventos de 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, em que 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. Durante a compilação, o multi-targeting combina as classes parciais para criar o comportamento específico de cada plataforma.
O processo para criar um comportamento de plataforma é o seguinte:
Crie uma classe parcial multiplataforma que define a API para o comportamento da plataforma.
Crie uma classe parcial nativa em cada plataforma para a qual seu aplicativo foi criado, que tem o mesmo nome da classe parcial multiplataforma. Essa classe parcial nativa deve herdar da classe PlatformBehavior<TView> ou PlatformBehavior<TView,TPlatformView>, em que
TView
é o controle multiplataforma ao qual o comportamento deve ser aplicado eTPlatformView
é a exibição nativa que implementa o controle multiplataforma em uma plataforma específica.Nota
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 modifica a espessura da borda de um controle nativo em algumas plataformas, mas não em todas.
Em cada classe parcial nativa que você precisa para implementar o comportamento da plataforma, você deve:
- Substitua o método OnAttachedTo para executar qualquer configuração.
- Substitua o método OnDetachedFrom para executar qualquer limpeza.
- Implemente a funcionalidade principal do comportamento da plataforma.
O comportamento pode ser consumido anexando-o à coleção Behaviors do controle.
Criar um comportamento de plataforma
Para criar um comportamento de plataforma, primeiro você deve criar uma classe parcial multiplataforma que define 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 TintColorBehavior
define uma única propriedade vinculável, TintColor
, que irá colorir uma imagem com a cor especificada.
Depois de criar a classe parcial multiplataforma, 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 filho necessárias da pasta Plataformas:
Como alternativa, você pode configurar seu projeto para dar suporte a multidirecionamento baseado em nome de arquivo, em pasta ou em ambos. Para mais informações sobre multidestinação, consulte Configurar multidestinação.
As classes parciais nativas devem herdar da classe PlatformBehavior<TView> ou da classe PlatformBehavior<TView,TPlatformView>, em que TView
é o controle multiplataforma ao qual o comportamento deve ser aplicado e TPlatformView
é a exibição nativa que implementa o controle multiplataforma em uma plataforma específica. Em cada classe parcial nativa necessária para implementar o comportamento da plataforma, você deve substituir o método OnAttachedTo e o método OnDetachedFrom e implementar a funcionalidade principal do comportamento da plataforma.
O método OnAttachedTo é chamado imediatamente após o comportamento da plataforma ser anexado a um controle multiplataforma. O método recebe uma referência ao controle multiplataforma ao qual está anexado e, opcionalmente, uma referência ao controle nativo que implementa o controle multiplataforma. O método pode ser usado para registrar manipuladores de eventos ou executar outra configuração necessária para dar suporte à funcionalidade de comportamento da plataforma. Por exemplo, você pode assinar um evento em um controle. A funcionalidade de comportamento seria então implementada no manipulador de eventos do evento.
O método OnDetachedFrom é chamado quando o comportamento é removido do controle multiplataforma. O método recebe uma referência ao controle ao qual está anexado e, opcionalmente, uma referência ao controle nativo que implementa o controle multiplataforma. O método deve ser usado para executar qualquer limpeza necessária. Por exemplo, você pode desinscrever-se de um evento em um controle para evitar vazamentos de memória.
Importante
As classes parciais devem residir no mesmo namespace e usar nomes idênticos.
O exemplo a seguir mostra a classe parcial TintColorBehavior
para Android, que unte 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 classe TintColorBehavior
deriva da classe PlatformBehavior<TView,TPlatformView>, em que TView
é um Image e TPlatformView
é um ImageView. O OnAttachedTo aplica a tonalidade à imagem, desde que a propriedade TintColor
tenha um valor. O método OnDetachedFrom remove a tinta da imagem.
Uma classe parcial nativa deve ser adicionada em cada plataforma para a qual você cria seu aplicativo. No entanto, você poderá tornar a classe parcial nativa NO-OP, se o comportamento da plataforma não for necessário em uma plataforma específica. Isso pode ser feito 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
de um comportamento de plataforma.
Adotar um comportamento de plataforma
Cada controle MAUI do .NET tem uma coleção Behaviors, à 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 Image equivalente 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 colorindo uma imagem:
Aviso
Os comportamentos da plataforma são gravados para um tipo de controle específico (ou uma superclasse que pode se aplicar a muitos controles) e eles só devem ser adicionados a um controle compatível. A tentativa de anexar um comportamento de plataforma a um controle incompatível resultará na geração de uma exceção.