No último post mostramos como animar transições usando o Blend e Visual States. Uma parte importante naquele mecanismo é o uso de behaviors. Com behaviors, podemos executar ações bastante complexas, apenas arrastando um behavior para um componente da janela. Isto, além de poderoso, traz outros benefícios:
- É reutilizável. Podemos incluir o mesmo behavior em diversas situações
- Permite que os designers possam incluir funcionalidade no design sem necessidade de código
Temos dois tipos de behaviors:
- Actions – executam uma ação associado a um evento. Por exemplo, você pode criar uma Action que, associada a uma TextBox, emite um “click” a cada tecla pressionada, ou outra action que faz um controle crescer quando o mouse está sobre ele
- Full behaviors – neste caso, há um comportamento mais complexo, não necessariamente associado a um único trigger. Um exemplo disso é o MouseDragElementBehavior, que permite movimentar um elemento, arrastando-o com o mouse
No Blend, encontramos os dois tipos de behaviors, com o final do nome indicando o tipo (ex. CallMethodAction ou FluidMoveBehavior).
Além dos pré-instalados, você pode encontrar outros behaviors, na galeria do Blend, em (quando verifiquei, existiam 114 behaviors disponíveis lá).
Os behaviors estão associados a um objeto e podem ter propriedades adicionais, além do trigger que os ativa. Por exemplo, o GoToStateAction tem como propriedades adicionais o componente destino e o estado a ser ativado, além da propriedade booleana UseTransitions, para usar as transições para mudar de um estado a outro.
Além de configurar as propriedades da Action, você pode especificar condições para que ela possa ser ativada. Por exemplo, usando o projeto do post anterior, podemos usar uma checkbox para permitir a ativação da transição. Para isso, basta clicar no botão “+” de Condition List, clicar no botão de propriedades avançadas da condição, criar um Data Binding com a checkbox e fazer um binding com a propriedade IsChecked. Desta maneira, a animação só será ativada se a checkbox estiver checada.
Além das Actions padrão, podemos criar Actions personalizadas para fazer o que queremos. No post anterior, usamos as Actions padrão, mas precisamos criar os Visual States. Além disso, temos um outro inconveniente: se quisermos fazer as animações para cima ou para baixo, temos que criar novos Visual States. Assim, criaremos nossa Action para fazer o que queremos, sem a necessidade de configuração especial.
No Visual Studio, crie um novo projeto WPF. Vamos adicionar agora a nossa Action. O Visual Studio, por padrão, não tem o template para criar uma Action. Poderíamos fazer isso usando o Blend. Ao abrir o projeto no Blend e selecionar a aba Project, você pode dar um clique com o botão direito do mouse, selecionar Add New Item e adicionar uma Action ao projeto.
Outra maneira de fazer isso é usar os templates online do Visual Studio. No Solution Explorer do Visual Studio, clique com o botão direito do mouse no projeto e selecione Add New Item. Na tela, vá para Online Templates e tecle action na caixa de pesquisa. Selecione o template C# Action Template for WPF e dê o nome de TransitionControlAction.
O template adiciona uma referência a System.Windows.Interactivity e gera uma classe semelhante a este código:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Interactivity;
namespace WpfApplication4
{
//
// If you want your Action to target elements other than its parent, extend your class
// from TargetedTriggerAction instead of from TriggerAction
//
public class TransitionControlAction : TriggerAction<DependencyObject>
{
public TransitionControlAction()
{
// Insert code required on object creation below this point.
}
protected override void Invoke(object o)
{
// Insert code that defines what the Action will do when triggered/invoked.
}
}
}
Temos dois tipos de actions: TriggerAction e TargetedTriggerAction. TriggerAction é uma action que não se refere a outro controle. Por exemplo, se quisermos criar uma action que executa o Notepad quando acontece um evento, usaríamos uma TriggerAction. TargetedTriggerAction refere-se a um outro elemento, chamado de Target. Este elemento é uma propriedade da action e pode ser acessado no Blend. Nós iremos criar uma TargetedTriggerAction. Portanto devemos mudar o código para derivar de TargetedTriggerAction, como mostra o comentário no início da classe. Esta action irá executar o mesmo código que criamos no primeiro post para fazer a animação. Devemos alterar também o tipo de objeto em que ela atua. Usaremos o FrameworkElement, pois este elemento tem as propriedades ActualWidthe ActualHeight.
public class TransitionControlAction : TargetedTriggerAction<FrameworkElement>
Inicialmente, iremos criar a enumeração para as posições e duas DependencyProperties com o tipo de animação desejada e a duração, de modo que ela possa ser selecionada no Blend.
public enum TipoAnimacao
{
Direita,
Esquerda,
Cima,
Baixo
}
[Category("Common Properties")]
public TipoAnimacao Tipo
{
get { return (TipoAnimacao)GetValue(TipoProperty); }
set { SetValue(TipoProperty, value); }
}
public static readonly DependencyProperty TipoProperty =
DependencyProperty.Register("Tipo", typeof(TipoAnimacao), typeof(TransitionControlAction));
[Category("Common Properties")]
public TimeSpan Duracao
{
get { return (TimeSpan)GetValue(DuracaoProperty); }
set { SetValue(DuracaoProperty, value); }
}
public static readonly DependencyProperty DuracaoProperty =
DependencyProperty.Register("Duracao", typeof(TimeSpan), typeof(TransitionControlAction),
new UIPropertyMetadata(TimeSpan.FromMilliseconds(500)));
Note que colocamos o atributo Category nas propriedades Tipo e Duraçãopara que elas apareçam junto com o grupo Common Properties. Ao compilarmos o projeto e abri-lo no Blend, vemos que nossa action aparece na aba Assets.
Ao arrastarmos uma TransitionControlAction para um botão, as propriedades aparecem no editor de propriedades:
Mas nossa action ainda não faz nada. Para fazer algo, devemos sobrescrever o método Invoke da action, colocando ali o código que deve ser executado. Usaremos o código que escrevemos na primeira postagem, modificando um pouco para usar o controle Target:
private void AnimaControle(FrameworkElement controle, TimeSpan duração, TipoAnimacao tipo)
{
double xFinal = 0;
double yFinal = 0;
if (tipo == TipoAnimacao.Esquerda)
xFinal = -controle.ActualWidth;
else if (tipo == TipoAnimacao.Direita)
xFinal = controle.ActualWidth;
else if (tipo == TipoAnimacao.Cima)
yFinal = -controle.ActualHeight;
else if (tipo == TipoAnimacao.Baixo)
yFinal = controle.ActualHeight;
// cria a transformação e atribui ao controle
var translate = new TranslateTransform(0, 0);
controle.RenderTransform = translate;
// cria a animação e anima-a
if (tipo == TipoAnimacao.Esquerda || tipo == TipoAnimacao.Direita)
{
var da = new DoubleAnimation(0, xFinal, new Duration(duração));
translate.BeginAnimation(TranslateTransform.XProperty, da);
}
else
{
var da = new DoubleAnimation(0, yFinal, new Duration(duração));
translate.BeginAnimation(TranslateTransform.YProperty, da);
}
}
Finalmente, basta chamar o método AnimaControle a partir do método Invoke:
protected override void Invoke(object o)
{
AnimaControle(Target, Duracao, Tipo);
}
Com isto, nosso behavior está completo. Podemos abrir o projeto no Blend, arrastar a action para o botão, configurar o objeto Target apontando para a grid e executar o projeto. Ao clicar o botão, a grid faz uma transição animada para a direção selecionada. Note que não precisamos fazer nada. Basta arrastar a action para o botão, configurar o elemento Target e as propriedades. A action está pronta para ser executada.
Conclusão
Foi um longo trajeto até aqui. Vimos quatro maneiras diferentes de animar a transição, começamos com código e terminamos usando o mesmo código. No meio do caminho vimos diversos conceitos: partir de um código fixo para um código mais refatorado e flexível, usar componentes para transição, eliminar o code behind usando MVVM, usando o Nuget, Templates Implícitos, usar Visual States para criar animações sem usar código e, finalmente, behaviors, para criar ações que podem ser usadas por designers, de maneira flexível e sem usar código. Espero que tenham gostado!
1 thought on “Animando transições em WPF/Silverlight–Parte IV–Behaviors”