Animando transições em WPF/Silverlight–Parte IV–Behaviors

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

image

Além dos pré-instalados, você pode encontrar outros behaviors, na galeria do Blend, em http://gallery.expression.microsoft.com (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.

image

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.

image

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.

image 

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.

image

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 ActualWidth e 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ção para 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.

image

Ao arrastarmos uma TransitionControlAction para um botão, as propriedades aparecem no editor de propriedades:

image

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.



image



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!

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>