I have crated a Blend behavior for Button. How can I set that to all of my Buttons in the app.
<Button ...>
<i:Interaction.Behaviors>
<local:MyBehavior />
</i:Interaction.Behaviors>
</Button>
However, when I try:
<Style>
<Setter Property="i:Interaction.Behaviors">
<Setter.Value>
<local:MyBehavior />
</Setter.Value>
</Setter>
</Style>
I get the error
The property "Behaviors" does not have an accessible setter.
I had the same problem and I've come up with a solution. I found this question after I solved it and I see that my solution bears a lot in common with Mark's. However, this approach is a little different.
The main problem is that behaviors and triggers associate with a specific object and so you cannot use the same instance of a behavior for multiple different associated objects. When you define your behavior inline XAML enforces this one-to-one relationship. However, when you try to set a behavior in a style, the style can be re-used for all the objects it applies to and this will throw exceptions in the base behavior classes. In fact the authors went to considerable effort to prevent us from even trying to do this, knowing that it wouldn't work.
The first problem is that we cannot even construct a behavior setter value because the constructor is internal. So we need our own behavior and trigger collection classes.
The next problem is that the behavior and trigger attached properties don't have setters and so they can only be added to with in-line XAML. This problem we solve with our own attached properties that manipulate the primary behavior and trigger properties.
The third problem is that our behavior collection is only good for a single style target. This we solve by utilizing a little-used XAML feature
x:Shared="False"
which creates a new copy of the resource each time it is referenced.The final problem is that behaviors and triggers are not like other style setters; we don't want to replace the old behaviors with the new behaviors because they could do wildly different things. So if we accept that once you add a behavior you cannot take it away (and that's the way behaviors currently work), we can conclude that behaviors and triggers should be additive and this can be handled by our attached properties.
Here is a sample using this approach:
The example uses triggers but behaviors work the same way. In the example, we show:
Here's an example behavior, our
DebugAction
. More properly it is an action but through the abuse of language we call behaviors, triggers and actions "behaviors".Finally, our collections and attached properties to make this all work. By analogy with
Interaction.Behaviors
, the property you target is calledSupplementaryInteraction.Behaviors
because by setting this property, you will add behaviors toInteraction.Behaviors
and likewise for triggers.and there you have it, fully-functional behaviors and triggers applied through styles.
I have another idea, to avoid the creation of a attached property for every behavior:
Behavior creator interface:
Small helper collection:
Helper class which attaches the behavior:
Now your behavior, which implements IBehaviorCreator:
And now use it in xaml:
1.Create Attached Property
2.Create a Behavior
3.Create a Style and set the attached property