AttachedBehavior pattern sample


The ClickBehavior is about the simplest I can think of.  For illustration purposes I only included one command, but LeftClickCommand, DoubleClickCommand, MouseOverCommand etc. are all obvious extensions:


  public static class ClickBehavior


    {


        public static DependencyProperty RightClickCommandProperty = DependencyProperty.RegisterAttached(“RightClick”,


                    typeof(ICommand),


                    typeof(ClickBehavior),


                    new FrameworkPropertyMetadata(null, new PropertyChangedCallback(ClickBehavior.RightClickChanged)));


 


        public static void SetRightClick(DependencyObject target, ICommand value)


        {


            target.SetValue(ClickBehavior.RightClickCommandProperty, value);


        }


 


        public static ICommand GetRightClick(DependencyObject target) {


            return (ICommand)target.GetValue(RightClickCommandProperty);


        }


 


 


        private static void RightClickChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)


        {


            UIElement element = target as UIElement;


            if (element != null)


            {


                // If we’re putting in a new command and there wasn’t one already


                // hook the event


                if ((e.NewValue != null) && (e.OldValue == null))


                {


                    element.MouseRightButtonUp += element_MouseRightButtonUp;


                }


                // If we’re clearing the command and it wasn’t already null


                // unhook the event


                else if ((e.NewValue == null) && (e.OldValue != null))


                {


                    element.MouseRightButtonUp -= element_MouseRightButtonUp;


                }


            }


        }


 


        static void element_MouseRightButtonUp(object sender, MouseButtonEventArgs e)


        {


            UIElement element = (UIElement)sender;


            ICommand command = (ICommand)element.GetValue(ClickBehavior.RightClickCommandProperty);


            command.Execute(null);


        }


    }


    public class DelegateCommand : ICommand


    {  


        public delegate void SimpleEventHandler();


        private SimpleEventHandler handler;


        private bool isEnabled = true;


 


        public event EventHandler CanExecuteChanged;


 


        public DelegateCommand(SimpleEventHandler handler)


        {


            this.handler = handler;


        }


 


        private void OnCanExecuteChanged()


        {


            if (this.CanExecuteChanged != null)


            {


                this.CanExecuteChanged(this, EventArgs.Empty);


            }


        }


 


        bool ICommand.CanExecute(object arg)


        {


            return this.IsEnabled;


        }


 


        void ICommand.Execute(object arg)


        {


            this.handler();


        }


 


        public bool IsEnabled


        {


            get


            {


                return this.isEnabled;


            }


            set


            {


                this.isEnabled = value;


                this.OnCanExecuteChanged();


            }


        }


    }


    public class ViewModel


    {


        public ICommand Foo


        {


            get


            {


                return new DelegateCommand(this.DoSomeAction);


            }


        }


 


        private void DoSomeAction()


        {


            MessageBox.Show(“Command Triggered”);


        }


    }


    public partial class Window1 : Window


    {


        public Window1()


        {


            InitializeComponent();


            this.DataContext = new ViewModel();


        }


 


    }


<Window x:Class=”WpfApplication1.Window1″


    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”


    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”


    xmlns:local=”clr-namespace:WpfApplication1″


    Title=”Window1″ Height=”300″ Width=”300″>


    <Grid>


        <Button Content=”Hello” local:ClickBehavior.RightClick=”{Binding Foo}”/>


    </Grid>


</Window>


 


Comments (4)

  1. Rob says:

    Great simple, yet practical example.  When I started building Caliburn, my first bits of functionality were very similar to this in implementation.

  2. joewood says:

    I like the pattern because you can build behavior independently of the inheritance hierarchy.  

    I’m now trying to think of how to implement this elegantly as a replacement for data triggers on live bound data.  I think it’s just a matter of casting the data context of the control and wiring it up accordingly.  But a better solution would probably be to use a class as the attached property and bind a property of that to the data itself – this way the behavior stays independent of the model.  Any thoughts?

  3. One cool thing about DependencyProperties is the ability to have AttachedDependencyProperties (or Attached