4

I have developed a behavior that changes the Clip property of the AssociatedObject. When I run the application, all is well. But when I view the page in Blend it appears like the behavior does not affect its associated object.

I tried to "debug" blend by attaching visual studio 2010 debugger to it's process and set a break point on the behavior's OnAttached method, but the breakpoint is never reached. As if blend prevents that behavior from being attached at design time.

Is there a way around it?

Cheers,

Kobi Hari
  • 1,259
  • 1
  • 10
  • 25
  • As far as I know, this problem is also there in WPF with Visual Studio 2013 (which has Blend integrated inside its designer). I've got to your issue since I have a similar situation in this environment. – FrankyB Jan 22 '15 at 13:37

2 Answers2

2

I finally found a workable way around it, but there's a big caveat which I put at the end of this answer. Here's my CustomAttachManager:

public class CustomAttachManager : DependencyObject
{
    #region Object CustomAttachManager.Attached = null

    public static IAttachedObject GetAttached(DependencyObject obj) { return (IAttachedObject)obj.GetValue(AttachedProperty); }
    public static void SetAttached(DependencyObject obj, IAttachedObject value) { obj.SetValue(AttachedProperty, value); }

    public static readonly DependencyProperty AttachedProperty =
        DependencyProperty.RegisterAttached("Attached", typeof(IAttachedObject), typeof(CustomAttachManager), new PropertyMetadata(null, StaticHandleAttachedChanged));

    static void StaticHandleAttachedChanged(DependencyObject self, DependencyPropertyChangedEventArgs args)
    {
        var ov = (IAttachedObject)args.OldValue;
        var nv = (IAttachedObject)args.NewValue;

        if (ov != null) ov.Detach();
        if (nv != null) nv.Attach(self);
    }
    #endregion
}

You can then use it to attach behaviors like this:

<my:CustomAttachManager.Attached>
    <my:RedBackgroundBehavior></my:RedBackgroundBehavior>
</my:CustomAttachManager.Attached>

My example behavior changes the background of a panel to red, which is visible in the designer.

The remaining problem is the case of multiple behaviors. The best solution I could come up with is a proxy:

[ContentProperty("Children")]
public class MultipleBehavior : Behavior<DependencyObject>
{
    DependencyObjectCollection<IAttachedObject> children = new DependencyObjectCollection<IAttachedObject>();
    public DependencyObjectCollection<IAttachedObject> Children { get { return children; } }

    protected override void OnAttached()
    {
        foreach (var child in Children) child.Attach(AssociatedObject);
    }

    protected override void OnDetaching()
    {
        foreach (var child in Children) child.Detach();
    }
}

which can be used this way:

    <my:CustomAttachManager.Attached>
        <my:MultipleBehavior>
            <my:RedBackgroundBehavior />
            <my:SupriseBehavior />
        </my:MultipleBehavior>
    </my:CustomAttachManager.Attached>

The proxy has a defect in that it won't properly handle behaviors added after something already got attached, but that is not going to happen in the classic use case.

The caveat is that I don't know a way to make Blend display the behaviors in the object tree. The "AlternateContentProperty" can't be used because it doesn't work for attached properties, which is what CustomAttachManager uses.

I will update this answer should I find an answer to this problem.

John
  • 6,693
  • 3
  • 51
  • 90
  • Thnx, John, that's actually a very good solution. I have also implemented my own behaviors collection for Win8 store applications (where there is no native behaviors support) and actually managed to get them working in design time, although with multiple behaviors there is the problem of passing the data context, as you have noticed in your solution. – Kobi Hari Dec 18 '13 at 15:40
  • @KobiHari If you have something linkable for what you've done with Win8 store xaml it would be cool if you post such link here. I've not yet experimented with that at all and how it compares to Silverlight; and maybe at some point in the future I will have to. – John Jan 19 '14 at 13:49
0

I'm not sure, but I think the associated object can only be affected once the behavior is "Attached". This is called during the "OnAttached" event and I do not believe that this event is invoked during design time. As far as I know, design time changes to controls happen during their initialization/creation phase. OnAttached happens after all of these occur (thus the reason the AssociatedObject is available for manipulation) and so as a result, makes it difficult for a behaviour to change a control at design time. I'm not saying it's impossible, but from the apparent design of a control's lifetime as well as a behaviour, this approach seems difficult. Solutions:

  • Take the approach of template manipulation. Attach a custom style or resource dictionary key that you design in a way that creates the impression you seek.
  • Create a custom control in Visual Studio that exposes a property that you can bind another control to. Let this custom control manipulate this "property", i.e., your control with the clip property during one of it's initialization methods. For example, during the InitializeComponent, check to see if the content is loaded, then call a method to adjust your "Clip" property as you so desire. Read up on the lifecycle of a silverlight control and this may help you - http://stuff.seans.com/2009/03/23/hello-silverlight-world-part-3-the-lifecycle-of-a-silverlight-control/

Like i said, i'm not sure of the answers here, but I will say this much - if the solution seems too complicated, there's probably a cleaner approach ;)

Neel Edwards
  • 308
  • 3
  • 7
  • Neel, as I wrote, I know that the behavior's OnAttached is not called, the question is why. There are a lot of different approaches that I can pick (for example, an attached property, which I tried, and which does work both on design time and run time). Since attached behaviors are based on attached properties, it seems a bit strange that they behave differently in design time. What I am wondering is if anybody knows why the OnAttached method is not called on design time and if there is something I can do different to make it called. – Kobi Hari Apr 15 '12 at 15:35
  • Ahh. I believe it'sjust not a part of the design time lifecycle. I remember runing into a similar situation when I was working on an ASP.NET project. I was doing a custom combo box whic i wanted to be slightly pre-poulated on design time, and it was then I realized that some methods, just aren't called until run time. I haven't been able to find documentation to say which methods are called at design time and which ones are called at run time. – Neel Edwards Apr 15 '12 at 17:31
  • My last bet is to make sure you're using DependencyProperties and not normal properties.Other than that, does it do the same in VS 2010? @KobiHari – Neel Edwards Apr 15 '12 at 17:39
  • Of course, only dependency properties. And, yes, it does the same in VS2010. – Kobi Hari Apr 16 '12 at 16:02
  • Well in that case, this seems like a Silverlight issue itself...Hopefully, someone figures out that answer then, since i must say, I'm stumped. @KobiHari – Neel Edwards Apr 16 '12 at 21:37