다음을 통해 공유


The Attached Behavior pattern

My favorite feature of WPF (desktop and web versions) is attached properties.  It would be good enough if attached properties merely enabled things like keeping layout properties (Canvas.Left) organized by the type of container rather than the type of content, but they also enable a great little design pattern:  Attached Behavior.

Nikhil recently blogged about behaviors in terms of Silverlight (https://www.nikhilk.net/Silverlight-Behaviors.aspx), but of course the same technique is available in desktop WPF and we widely used it during Expression development.  Nikhil describes the technique well, but let me reiterate in Design Patternese:

The Attached Behavior pattern encapsulates "behavior" (usually user interactivity) into a class outside the visual heirarchy and allows it to be applied to a visual element by setting an attached property and hooking various events on the visual element.

One of the first behaviors we wrote in Blend was the ClickBehavior.  The M-V-VM pattern uses Commands instead of events in many cases, but WPF controls don't trigger Commands in all the interesting cases.  Button for example has a Command property, but it only fires when the Button is clicked, not double-clicked or right-clicked.  ClickBehavior defines attached properties like DoubleClickCommand of type Command.  When you set these properties the behavior registers for the MouseRightButtonUp event and in the handler for that event invokes the Command in the DoubleClickCommand behavior.  Interestingly, this same behavior can be used to attach Commands to *any* UIElement, even a rectangle.  This turns out to be useful for adding interactivity to parts of the UI without the extra cost of a full-blown Control. 

You can do a lot with the Attached Behavior pattern.  Drag and drop is an obvious candidate for a behavior.  A single DragDropBehavior class can register for all the basic input events and invoke Commands like OnDrop and OnDrag, allowing you to make any visual a DropTarget or DropSource without sub-classing or adding substantial code to your page.  As I mentioned in my previous post, Silverlight's Parts and States model does not work easily with the built-in desktop WPF controls because those controls do not trigger the state changes.  An attached behavior can hook the right events and do the state transitions...the first prototype of the Silverlight model was written in desktop WPF as an attached behavior. 

More on this pattern later.

Comments

  • Anonymous
    May 07, 2008
    Caliburn uses the same pattern to add most of its functionality.  It's used to enable MVP, loosely coupled ui composition, ui state persistence, lazy module loading, etc.  This would all be possible without attached properties, however it would be much more painful.  So, I was very glad when attached properties showed up in the SL 2 Beta 1.

  • Anonymous
    May 07, 2008
    Interesting, would the default control templates in WPF be migrated to this new pattern?

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

  • Anonymous
    May 08, 2008
    WPF Controls Emphess.Net: A MenuKiller Control - this article is a work in progress detailing how to

  • Anonymous
    May 09, 2008
    John, Thanks for your response on the other post about ICommand and I look forward to seeing your example. I do have another question about Behaviors that seems to be an issue with SL that you might be able to provide some background on if you are willing.   In the desktop framework, DependencyObject has a .ctor() that is public but in SL, you have to go all the way down the inheritance tree to System.Windows.Controls.Control to find a public .ctor() Why is that?  I am running into this in using Prism on SL also, not just with behaviors.   In addition there is a mismatch between the apis for DepenencyProperty.RegisterAttached between desktop and SL that seems to require two different codebases (#if SILVERLIGHT...#else....$endif) which I really don't like. Thanks again.

  • Anonymous
    May 09, 2008
    Mark, In Beta 2 (coming soon), you will find the RegisterAttached API difference has been fixed.  We have not made DO.ctor() public on the principal of exposing the least surface area possible, but this has proven problematic.  What is the exact scenario you have for wanting your own DO subclass?

  • Anonymous
    May 09, 2008
    John, So far I have run into it twice, three times if you count the Behavior subclass from Nikhil's article. 1(&2).  I was implementing Behaviors myself and was trying to subclass DependencyObject when I ran into your article which linked me to Nikhil's.  Like my implementation he was forced to sub-class from Control in SL.

  1.  I am doing some spikes involving creating some base classes for use in a MVVP DataModel where the base class for the Data Model objects is a DependencyObject.  Now I am not even sure this ia good idea at this point which is why I am asking. :) As a more general point I am finding the constrained SL API's somewhat challenging to use not because I can't figure out how to do what I want but because many of the programming idoms that make up the '.NET WAY" have changed and there is no clear commentary on what to replace it with.  Case(s) in point:
  • ICommand - pattern is good, Desktop implementation of RoutedEvents is complicated, but no ICommand interface - what now?

  • SerializableAttribute - Replaced with the preferd WCF Serialization which is good but it did take a bit to figure that out. And of course it leave me with incompatible desktop code unless I move everything over to use DataContract. The DLR on SL even duplicates this attribute in its own assembly (Microsoft.Scripting)

  • StringSplitOptions - again missing from SL and duplicated in DLR

  • there are more... Please understand I am NOT complaining.  Just trying to understand the new SL pattern guidance, which is why I was really glad to find your blog because it appears you are starting to answer some of those questions. Thanks again.

  • Anonymous
    May 09, 2008
    Great feedback...we're running so fast here we're missing some things.  

  • Anonymous
    May 13, 2008
    Thanks John. I know you are pretty busy but I just ran into another example - in SL the approach taken has to implement the Async Event Pattern as described here, http://msdn.microsoft.com/en-us/library/wewwczdw.aspx and seen in the WebClient. I have implemented code on the desktop to do that but when porting to SL I run into a problem because AsyncOperation and AsyncOperationManager classes don't exist.  It appears special versions of them do exist for ClientBase WCF calls but they are not general use and they are internal. Again, this is not a matter of asking that these classes be put back but simply trying to figure out what 'pattern' should be used to implement Async API's that are usable on both desktop and SL. Thanks

  • Anonymous
    May 13, 2008
    Good question about Async...I will ask the authorities.

  • Anonymous
    May 13, 2008
    Mark, We added AsyncOperation and AsyncOperationManager into SL.  They’ll make Beta2.  More good news...we are planning to make the ctor for DependencyObject public, though that will not make Beta2.

  • Anonymous
    May 13, 2008
    John, That is good news!  Thanks.   Any word on ICommand?

  • Anonymous
    August 08, 2008
    As I’ve described before , we introduced the new VisualStateManager concept into Silverlight WPF before

  • Anonymous
    January 12, 2009
    The comment has been removed

  • Anonymous
    February 11, 2009
    In this post, I'm going to describe an implementation of ICollectionView for Silverlight that allows

  • Anonymous
    February 15, 2009
    In this article I will explain how to implement MVVM pattern in Silverlight. I was very overjoyed when

  • Anonymous
    February 15, 2009
    I was working on a WPF project the other day and wanted an easy way to display data in a simple tabular

  • Anonymous
    April 10, 2009
    Launching a custom dialog for editing on the DataGrid is another somewhat common request that I see from

  • Anonymous
    April 13, 2009
    Lorsque l’on travaille avec WPF et le pattern MVVM (Model View ViewModel), on essaye d’éviter au maximum

  • Anonymous
    May 05, 2009
    Uno dei primi “scogli” in cui ci si scaglia contro durante lo studio del Model-View-ViewModel è la visualizzazione