Para começar, é necessário incluir no seu projeto uma referencia para o assembly Microsoft.Expression.Interactivity.dll, este assembly fica localizado na pasta {Program Files}\Microsoft Expression\Blend 3 Preview\Libraries\Silverlight\Microsoft.Expression.Interactivity.dll ( ou pode ser baixado através do link ). Por algum motivo este assembly não faz parte do SDK do Silverlight até o momento.

Dentro deste assembly existem 3 classes que voce pode usar como base para criar seus proprios behaviors:

        
  • Behavior: Behavior simples

  •     
  • TriggerAction: Behavior disparado com eventos

  •     
  • TargettedTriggerAction: Behavior disparado com eventos que afeta objetos separados ( Targets )


O diagrama de classe fica da seguinte maneira:



Neste post vamos criar um behavior simples que usa como base a classe Behavior. Para behaviors simples esta classe é perfeita, o unico trabalho que temos que fazer é implementar dois metodos para notificar o behavior quando ele é anexado e desanexado de um objeto.  Eu decidi criar um behavior que será aplicado em Panels ( Componentes que são usados para gerenciamento de layout: Canvas, StackPanel e Grid ), a ideia deste behavior é que quando o usuário entrar com o mouse sobre um dos filhos do panel ( componentes dentro do panel: button,list,... ), os outros fiquem transparente ( próximo do invisivel ), e quando o usuário sair  com o mouse, os filhos voltem com sua cor original.

Então para começar crie uma classe que extende a classe Behavior, eu dei o nome de PanelFocusBehavior.



public class PanelFocusBehavior : Behavior



O metodo Behavior possui 2 metodos (OnAttached e OnDetaching) que vamos sobrescrever para adicionar
a nossa lógica.
OnAttached: Este método é executado no momento em que o behavior é associado a um objeto da aplicação.
OnDetaching: Este metodo é executado quando o a associação entre o behavior e o objeto deixa de existir.

Veja a implementação do método OnAttached para o nosso behavior:



        private Panel panel;
        private Dictionary childrenOpacityMask;
        protected override void OnAttached()
        {
            base.OnAttached();
            panel = this.AssociatedObject;
            childrenOpacityMask = new Dictionary();
            panel.Loaded += new RoutedEventHandler(panel_Loaded);

        }        

        void panel_Loaded(object sender, RoutedEventArgs e)
        {
            foreach (UIElement children in panel.Children)
            {
                children.MouseEnter += new MouseEventHandler(children_MouseEnter);
                children.MouseLeave += new MouseEventHandler(children_MouseLeave);
                childrenOpacityMask.Add(children, children.OpacityMask);
            }
        }



Veja que no metodo OnAttached a única coisa que fazemos é guardar a referencia para o Panel que esta
sendo associado ao nosso behavior e adicionar um handler para o evento Loaded deste panel.

No metodo panel_Loaded percorremos todos os filhos ( objetos dentro do panel ) e adicionamos um handler
para o evento MouseEnter e outro para o evento MouseLeave. Também adicionamos em um Dictionary a mascara
original do objeto ( Este passo é importante para que o aspecto original do objeto seja mantido durante a
execução do behavior ).

Ok, depois de iniciarmos o behavior e adicionar um handler para os eventos dos filhos, o que falta?
Falta ainda, realizar as alterações que havia idealizado para o Panel. Veja a lógica dos metodos MouseEnter e MouseLeave.


        void children_MouseEnter(object sender, MouseEventArgs e)
        {
            Brush oldOpacityMask;
            SolidColorBrush opacityMask = new SolidColorBrush(Color.FromArgb(40,255,255,255));
            foreach (UIElement children in panel.Children)
            {
                children.OpacityMask = opacityMask;
            }

            UIElement elementSender = (sender as UIElement);
            if (childrenOpacityMask.TryGetValue(elementSender, out oldOpacityMask) == true)
            {
                elementSender.OpacityMask = oldOpacityMask;
            }
        }

        void children_MouseLeave(object sender, MouseEventArgs e)
        {
            foreach (UIElement children in panel.Children)
            {
                restoreColor(children);
            }
        }

        private void restoreColor(UIElement element)
        {
            Brush opacityMask;
            if (childrenOpacityMask.TryGetValue(element, out opacityMask) == true)
            {
                element.OpacityMask = opacityMask;
            }
        }


No metodo children_MouseEnter percorremos todos os objetos que estão no panel e trocamos
a OpacityMask de cada um para um SolidColorBrush com alpha 40. Depois de percorrer todos, voltamos a
mascara do objeto que disparou o evento para sua mascara original ( deste modo somente ele irá permanecer
com sua aparencia original )

No metodo children_MouseLeave percorremos todos os objetos que estão no panel e voltamos
sua mascara original.

O metodo restore color, só serve para voltar a aparencia original de um objeto.

Ok. Nós já vimos no post anterior como aplicar os behaviors. Portanto agora basta adicionar este behavior
em um Panel qualquer e testar. Veja figura do nosso behavior em ação.
bvs1

Para quem não conseguiu acompanhar o tutorial, veja o código completo do nosso Behavior:


using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Expression.Interactivity;
using System.Collections;
using System.Collections.Generic;

namespace BehaviorsDemo
{
    public class PanelFocusBehavior : Behavior
    {
        private Panel panel;
        private Dictionary childrenOpacityMask;
        protected override void OnAttached()
        {
            base.OnAttached();
            panel = this.AssociatedObject;
            childrenOpacityMask = new Dictionary();
            panel.Loaded += new RoutedEventHandler(panel_Loaded);

        }        

        void panel_Loaded(object sender, RoutedEventArgs e)
        {
            foreach (UIElement children in panel.Children)
            {
                children.MouseEnter += new MouseEventHandler(children_MouseEnter);
                children.MouseLeave += new MouseEventHandler(children_MouseLeave);
                childrenOpacityMask.Add(children, children.OpacityMask);
            }
        }

        protected override void OnDetaching()
        {
            foreach (UIElement children in panel.Children)
            {
                children.MouseEnter -= new MouseEventHandler(children_MouseEnter);
                children.MouseLeave -= new MouseEventHandler(children_MouseLeave);
                restoreColor(children);
            }
        }

        void children_MouseLeave(object sender, MouseEventArgs e)
        {
            foreach (UIElement children in panel.Children)
            {
                restoreColor(children);
            }
        }

        void children_MouseEnter(object sender, MouseEventArgs e)
        {
            Brush oldOpacityMask;
            SolidColorBrush opacityMask = new SolidColorBrush(Color.FromArgb(40,255,255,255));
            foreach (UIElement children in panel.Children)
            {
                children.OpacityMask = opacityMask;
            }

            UIElement elementSender = (sender as UIElement);
            if (childrenOpacityMask.TryGetValue(elementSender, out oldOpacityMask) == true)
            {
                elementSender.OpacityMask = oldOpacityMask;
            }
        }

        private void restoreColor(UIElement element)
        {
            Brush opacityMask;
            if (childrenOpacityMask.TryGetValue(element, out opacityMask) == true)
            {
                element.OpacityMask = opacityMask;
            }
        }
    }
}



O interessante é que agora podemos adicionar este comportamento em qualquer Panel da nossa aplicação sem a necessidade de alterar código. Basta arrastar o Behavior e pronto.
Nos próximos posts sobre o tema vamos ver como criar Behaviors através da classe TriggerAction.