Del via


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="https://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="https://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

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

  • Anonymous
    May 16, 2008
    PingBack from http://dogs-pets.info/dog-breeding/?p=959

  • Anonymous
    May 19, 2008
    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?

  • Anonymous
    May 27, 2009
    One cool thing about DependencyProperties is the ability to have AttachedDependencyProperties (or Attached