问题
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,
回答1:
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.
回答2:
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 ;)
来源:https://stackoverflow.com/questions/10154023/silverlight-blend-behaviors-do-not-get-attached-at-design-time