混合行为 - 你能绑定它们的属性吗?

7

我目前正在将我创建的一些附加行为迁移到Blend Behaviours,以便它们支持Expression Blend中的拖放。我注意到Blend行为的作者倾向于将行为属性定义为依赖属性。

我创建了一个名为TiltBehaviour的行为,它公开了一个类型为double的公共依赖属性TiltFactor。在Expression Blend中,我可以设置此属性的值,但是“添加数据绑定…”选项被禁用:

cannot bind to behaviour property

我还注意到,行为扩展了DependencyObject,因此它们没有DataContext,因此不能继承它们所附加到的元素的DataContext。这对我来说感觉像是一个真正的弱点!

因此,问题的关键是,如果我无法在Blend中将我的行为依赖属性绑定,并且它不会继承DataContext,那么为什么要使用依赖属性呢?我可以使用CLR属性代替。


1
非常奇怪,它是哪个版本的Blend?我使用Blend 4 + Silverlight 4将元素属性或DataContext属性绑定到Behaviors的依赖属性时没有任何问题... - dain
Dain,我已经尝试在Visual Studio中手动绑定,例如TiltFactor =“{Binding}”,但结果是AG_E_PARSER_BAD_PROPERTY_VALUE,这通常表示您正在绑定到非依赖属性。您能否指出一个在网络上绑定行为属性的示例? - ColinE
1
你必须绑定到正确类型的具体属性:TiltFactor="{Binding TiltFactor}"。 - dain
Dain...这取决于您的DataContext是什么,在我上面的示例中,我正在将我附加到的元素的DataContext设置为double,例如Rectangle.DataContext = 10.0,因此没有属性路径的TiltFactor =“{Binding}”绑定是完全有效的。无论如何,我尝试了您的建议TiltFactor =“{Binding TiltFactor}”,但仍然没有成功!也许这是VS / Silverlight for Windows Phone 7中的特定问题。 - ColinE
1
啊,抱歉...我没有更多的想法了,即使是隐式继承的 DataContext,在我的 SL4 上也可以工作。 - dain
没问题 - 谢谢你的帮助。我只需要尝试一下SL4而已 :-/ 至少我知道它应该可以工作,并且这些属性应该是DP的原因非常充分。 - ColinE
2个回答

8

如果 Blend 行为不支持绑定,那么它们几乎没有用处!我重新创建了您的倾斜行为,并且在 Blend 4 中支持绑定,没有任何问题,所以我不知道您出了什么问题。也许您可以重现我的简单示例,然后推断出您的设置有什么问题。

以下是(无效的)具有依赖属性的倾斜行为:

public class TiltBehavior : Behavior<FrameworkElement>
{
    public double TiltFactor
    {
        get { return (double)GetValue(TiltFactorProperty); }
        set { SetValue(TiltFactorProperty, value); }
    }

    public static readonly DependencyProperty TiltFactorProperty =
        DependencyProperty.Register("TiltFactor", typeof(double), typeof(TiltBehavior), new UIPropertyMetadata(0.0));
}

然后创建一个新窗口并将行为拖放到网格上,Blend就会创建出这样的效果:

<Grid>
    <i:Interaction.Behaviors>
        <local:TiltBehavior/>
    </i:Interaction.Behaviors>
</Grid>

在属性选项卡中,Blend的“数据绑定...”选项可用。

我已经在WPF和Silverlight项目中进行了测试。内置的行为、触发器和动作都支持绑定,因为它们都是依赖属性,并且所有Blend示例都大量使用绑定,所以这一点必须要有效。

实际上,您只需将内置行为(例如FluidMoveBehavior)拖放到网格上并检查其是否支持绑定(例如依赖属性Duration),即可验证其是否支持绑定。如果这样做不起作用,那我就无能为力了!


那么我们来考虑一下绑定如何适用于这些奇怪的行为。

作为WPF或Silverlight程序员,我们非常熟悉为FrameworkElement等事物绑定。它有一个称为DataContext的属性,我们可以操纵它来控制默认的绑定源,并且当我们没有覆盖它时,该属性会被嵌套元素继承。

但是行为(以及触发器和动作)不是FrameworkElement类型。它们最终是从DependencyObject派生出来的,这是我们所期望的。但是,虽然我们可以在DependencyObject任何派生类上使用绑定,但在这个低级别上,我们熟悉的DataContext缺失了,因此绑定必须提供源。 这并不方便。

因此,在WPF中,行为是从Animatable派生出来的,而Animatable又是从Freezable派生出来的。 Freezable类是简单的依赖对象与框架元素复杂性相交的地方。 Freezable类也是更熟悉的东西(例如画笔和图像源)的基类。这些类不需要框架元素的全部复杂性,但它们希望以一种有限的方式参与与其相关联的元素。

通过一个复杂的魔法过程,Freezable实例获得继承上下文:它们最密切关联的框架元素,并且当使用默认绑定(没有源)时,Freezable使用其关联元素的DataContext

实际上,当您学习行为时,AssociatedObject是一个核心概念;对于行为,它是行为所附加的对象。 但重要的一点是,所有Freezable对象都可以通过代理使用其AssociatedObjectDataContext

所有这些魔法就是Josh Smith所说的:

由于Hillberg Freezable Trick,因此Blend行为支持使用关联元素的数据上下文作为默认来源进行绑定。这意味着,行为的绑定似乎“自动工作”,无需我们进行任何努力。正是由于此,行为变得更加实用。


4

编辑:dain是正确的,您仍然可以绑定到人工创建的DataContext,您有多少次看到人们绑定到SolidColorBrush.Color?即使SolidColorBrush从DependencyObject继承并且没有DataContext,它也可以工作。

请参见这篇关于继承上下文的博客文章

问题在于,由于行为是附加的,它们不会出现在逻辑树中,因此无论如何都不会继承DataContext。


对于继承上下文的博客文章点个赞。为什么我以前没看到过?!太棒了。 - ColinE
然而...它们可以继承DataContext,就像这篇博客文章中所述:http://www.scottlogic.co.uk/blog/colin/2010/05/silverlight-multibinding-solution-for-silverlight-4/ - ColinE
很奇怪,这些信息要么没有在文档中提到,要么非常难找到。 - H.B.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接