Comportamentos
Procurar a de exemplo
Os comportamentos .NET Multi-platform App UI (.NET MAUI) permitem adicionar funcionalidade extra aos controles da 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.
Os comportamentos podem ser usados para adicionar diferentes funcionalidades aos controles da interface do usuário, como:
- Validações de entrada. Os 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 número de telefone ou endereço de email esteja no formato correto.
- Aprimorando a interface do usuário. Os comportamentos podem ser usados para aprimorar os controles da interface do usuário em seu aplicativo. Por exemplo, você pode escrever um comportamento para um Button para fazê-lo tremer quando for clicado ou alterar a cor.
- Respostas em tempo de execução. Os comportamentos podem ser usados para fazer com que os controles reajam a diferentes situações. Por exemplo, você pode salvar automaticamente a entrada do usuário em um Entry quando um usuário terminar de digitar.
O .NET MAUI suporta três tipos diferentes de comportamentos:
- Comportamentos anexados são classes
static
com uma ou mais propriedades associadas. Para obter mais informações sobre comportamentos anexados, consulte Comportamentos anexados. - Os comportamentos MAUI do .NET são classes que derivam da classe Behavior ou Behavior<T>, onde
T
é o tipo de controle ao qual o comportamento deve ser aplicado. Para mais informações, consulte Comportamentos do .NET MAUI. - Os comportamentos de plataforma são classes que derivam da classe PlatformBehavior<TView> 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 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 numa certa classe, mas associados 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 ponto final. Para obter mais informações sobre propriedades anexadas, consulte Propriedades anexadas.
Uma propriedade anexada pode definir um propertyChanged
delegado que será executado quando o valor da propriedade for alterado, como quando a propriedade for definida em um controle. Quando o delegado propertyChanged
é executado, é-lhe passada uma referência ao controlo ao qual está a ser anexado, bem como parâmetros que contêm os valores antigos e novos da propriedade. Esse delegado pode ser usado para adicionar nova funcionalidade ao controle ao qual a propriedade está anexada, manipulando a referência que é passada, da seguinte maneira:
- O delegado de
propertyChanged
converte a referência de controle, que é recebida como um BindableObject, para o tipo de controle que o comportamento foi projetado para aprimorar. - O delegado de
propertyChanged
modifica as 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.
Advertência
Os comportamentos anexados são definidos numa classe static
, com static
propriedades e métodos. Isso dificulta a criação de comportamentos associados que tenham 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 classe AttachedNumericValidationBehavior
, que destaca 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 cancela o registro de um manipulador de eventos para o evento TextChanged
, com base no valor da propriedade AttachBehavior
anexada. A funcionalidade principal do comportamento é fornecida pelo método OnEntryTextChanged
, que analisa o valor inserido no Entry e define a propriedade TextColor
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 como consumir a classe AttachedNumericValidationBehavior
em um Entry ao adicionar a propriedade anexada 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 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 à entrada inválida:
Observação
Os 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 classe AttachedNumericValidationBehavior
pode ser removida de um controle definindo a propriedade AttachBehavior
anexada como false
:
<Entry Placeholder="Enter a System.Double" local:AttachedNumericValidationBehavior.AttachBehavior="false" />
No tempo de execução, o método OnAttachBehaviorChanged
será executado quando o valor da propriedade AttachBehavior
anexada for definido como false
. O método OnAttachBehaviorChanged
cancelará o registro do manipulador de eventos para o 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 .NET MAUI é o seguinte:
- Crie uma classe que herda da classe Behavior ou Behavior<T>, onde
T
é o tipo de 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 é 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 se inscrever em um evento em um controle. A funcionalidade de comportamento seria então implementada no manipulador de eventos para o evento.
O método OnDetachingFrom é chamado quando o comportamento é removido do controle. Este método recebe uma referência ao controle ao qual está anexado e é usado para executar qualquer limpeza necessária. Por exemplo, pode-se remover a subscrição de um evento num controlo para evitar vazamentos de memória.
O comportamento pode então ser consumido anexando-o à coleção Behaviors do controle.
Criar um comportamento .NET MAUI
Um comportamento .NET MAUI 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 destaca 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>, onde T
é um Entry. 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 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 vermelho se o valor não for um double
.
Importante
O .NET MAUI não define o BindingContext
de um comportamento, porque os comportamentos podem ser compartilhados e aplicados a vários controles por meio de estilos.
Consumir um comportamento .NET MAUI
Cada controle .NET MAUI 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 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 à entrada inválida:
Advertência
Os comportamentos do .NET MAUI 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. 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 do .NET MAUI com estilo
Os comportamentos do .NET MAUI podem ser consumidos por um estilo explícito ou implícito. No entanto, criar 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. Certifique-se de que a propriedade anexada registre um delegado
propertyChanged
que será executado quando o valor da propriedade se alterar. - Crie um
static
getter e setter para a propriedade anexada. - Implemente a lógica no
propertyChanged
delegado 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 para o controle, com base no valor da propriedade AttachBehavior
anexada.
O exemplo de código a seguir mostra um estilo explícito de
<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 para o 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 Estilos.
Observação
Embora você possa adicionar propriedades vinculáveis a um comportamento definido ou consultado em XAML, se você criar comportamentos que tenham estado, eles não devem ser compartilhados entre controles em um Style em 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 assinatura de um evento para evitar um vazamento de memória. No entanto, os comportamentos não são implicitamente removidos dos controles, a menos que a coleção de 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 de Behaviors do controlador pode ser limpa:
entry.Behaviors.Clear();
Observação
Os comportamentos do .NET MAUI não são implicitamente removidos dos controles quando as páginas são removidas da pilha de navegação. Em vez disso, eles devem ser explicitamente removidos antes que as páginas saiam do escopo.
Comportamentos da plataforma
Os comportamentos da plataforma são criados derivando da classe PlatformBehavior<TView> 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 entre plataformas que define a API de comportamentos e uma classe parcial nativa que implementa o comportamento em cada plataforma. No momento da compilação, a segmentação múltipla combina as classes parciais para criar o comportamento da plataforma em cada plataforma.
O processo para criar um comportamento de plataforma é o seguinte:
Crie uma classe parcial entre plataformas que defina a API para o comportamento da plataforma.
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 classe PlatformBehavior<TView> ou PlatformBehavior<TView,TPlatformView>, onde
TView
é o controle de plataforma cruzada ao qual o comportamento deve se aplicar eTPlatformView
é a exibição nativa que implementa o controle de plataforma cruzada em uma plataforma específica.Observação
Embora seja necessário criar uma classe parcial nativa em cada plataforma para a qual seu aplicativo é criado, não é necessário implementar a funcionalidade de comportamento da plataforma em cada plataforma. Por exemplo, você pode criar um comportamento de plataforma que modifique a espessura da borda de um controle nativo em algumas, mas não todas, plataformas.
Em cada classe parcial nativa necessária 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 então ser consumido anexando-o à coleção Behaviors do controle.
Criar um comportamento de plataforma
Para criar um comportamento de plataforma, você deve primeiro criar uma classe parcial entre plataformas 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 matizará uma imagem com a cor especificada.
Depois de criar a classe parcial entre plataformas, 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 subpastas necessárias da pasta Platforms.
Como alternativa, você pode configurar seu projeto para oferecer suporte à multisegmentação baseada em nome de arquivo, à multisegmentação baseada em pasta ou a ambas. Para mais informações sobre multialvo, consulte Configurar multialvo.
As classes parciais nativas devem herdar da classe PlatformBehavior<TView> ou da classe PlatformBehavior<TView,TPlatformView>, onde TView
é o controle entre plataformas ao qual o comportamento deve se aplicar e TPlatformView
é a visã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 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 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 dar suporte à funcionalidade de comportamento da plataforma. Por exemplo, você pode se inscrever em um evento em um controle. A funcionalidade de comportamento seria então implementada no manipulador de eventos para o evento.
O método OnDetachedFrom é chamado quando o comportamento é removido do controlo 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, pode-se desinscrever-se de um evento num controlo 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 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 classe TintColorBehavior
deriva da classe PlatformBehavior<TView,TPlatformView>, onde TView
é um Image e TPlatformView
é um ImageView. O OnAttachedTo aplica o tom à imagem, desde que a propriedade TintColor
tenha um valor. O método OnDetachedFrom remove a tonalidade da imagem.
Uma classe parcial nativa deve ser adicionada em cada plataforma para a qual você cria seu aplicativo. No entanto, pode definir a classe parcial nativa como "NO-OP" se o comportamento da plataforma não for necessário numa plataforma específica. Isto pode ser conseguido 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.
Consumir um padrão de comportamento de plataforma
Cada controle .NET MAUI 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.
Advertência
Os comportamentos de plataforma 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. A tentativa de anexar um comportamento de plataforma a um controle incompatível resultará em uma exceção sendo lançada.