在 WPF 中,为啥 TemplateBinding 不能在 Binding 的地方工作?

Posted

技术标签:

【中文标题】在 WPF 中,为啥 TemplateBinding 不能在 Binding 的地方工作?【英文标题】:In WPF, why doesn't TemplateBinding work where Binding does?在 WPF 中,为什么 TemplateBinding 不能在 Binding 的地方工作? 【发布时间】:2011-08-20 06:26:45 【问题描述】:

好吧...这让我摸不着头脑。我有两个 WPF 控件——一个是用户控件,另一个是自定义控件。我们称它们为 UserFoo 和 CustomFoo。在 CustomFoo 的控制模板中,我使用了一个 UserFoo 实例,它是一个命名部分,因此我可以在应用模板后访问它。效果很好。

现在 UserFoo 和 CustomFoo 都定义了一个 Text 属性(独立地,即不是使用 AddOwner 的共享 DP。别问...)都这样声明...

public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
    "Text",
    typeof(string),
    typeof(UserFoo), // The other is CustomFoo
    new FrameworkPropertyMetadata(
        null,
        FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
        null,
        null,
        true,
        UpdateSourceTrigger.PropertyChanged
    )
);

请注意,模式设置为 TwoWay,UpdateSourceTrigger 设置为 PropertyChanged,同样适用于两者。

所以在 CustomFoo 的样式模板中,我想将 CustomFoo 的 Text 属性作为源绑定到内部 UserFoo 的 Text 属性。通常,这很容易。您只需将 UserFoo 的 text 属性设置为“TemplateBinding Text”,但由于某种原因,它只是一种方式(即,UserFoo 是从 CustomFoo 正确设置的,但不是相反的),即使再一次,两个 DP 都设置为双向!但是,当使用相对源绑定而不是模板绑定时,效果很好!嗯……什么??

// This one works
Text="Binding Text, RelativeSource=RelativeSource AncestorType=local:CustomFoo, Mode=TwoWay"

// As does this too...
Text="Binding Text, RelativeSource=RelativeSource TemplatedParent, Mode=TwoWay"

// But not this one!
Text="TemplateBinding Text"

那是什么?我错过了什么?

【问题讨论】:

如果您使用可以指定模式的长版 TemplateBinding 会发生什么? IE:Text="Binding RelativeSource=RelativeSource TemplatedParent, Path=Text, Mode=TwoWay" - 这将告诉我们是模式问题还是 TemplateBinding 问题 如果你看上面,我说长版本工作得很好。 (为了清晰起见,我添加了一个使用 TemplatedParent 而不是显式设置控件类型的第二个实例。)再次,短版本确实设置了 UserFoo 的文本,因为它应该......它只是对 UserFoo 的更改不会反映回 CustomFoo . 如果您有具体问题,请发送至Meta Stack Overflow,并请阅读faq @Jeff... 什么?这不是元数据的问题。是为了这里。如果您是因举报而惩罚我的版主,询问我为什么因拒绝不良信息而失去声誉,那是因为在 SO Meta FAQ 的最顶部,它说“最重要的是,说实话。如果您看到错误信息,请投票向下。添加 cmets 来指出具体的错误。提供您自己的更好的答案。最重要的是 - 编辑和改进现有的问题和答案!”这正是我所做的,为什么我会受到惩罚? 【参考方案1】:

在 MSDN 上找到此论坛帖子:http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/0bb3858c-30d6-4c3d-93bd-35ad0bb36bb4/

上面写着:

TemplateBinding 是针对模板场景的 Binding 优化形式,类似于用

构造的 Binding
Binding RelativeSource=RelativeSource TemplatedParent

来自 OP 的注释:与文档中所说的相反,实际上,它应该是这个......

Binding RelativeSource=RelativeSource TemplatedParent, Mode=OneWay

我对文档提出了投诉,虽然他们现在确实添加了一句话,说明它们始终是单向的,但代码示例仍然没有列出模式,但我想总比没有好。)

TemplateBinding 将数据从模板化父级传输到模板绑定的属性。如果您需要反向或双向传输数据,请使用 TemplatedParent 的 RelativeSource 创建一个 Binding,并将 Mode 属性设置为 OneWayToSource 或 TwoWay。

更多内容:http://msdn.microsoft.com/en-us/library/ms742882.aspx

看起来 Mode=OneWay 是使用 TemplateBinding 的“优化”之一

【讨论】:

实际上,如果您查看 MSDN 链接,它并没有说明是 OneWay,只是 "Binding RelativeSource=RelativeSource TemplatedParent" 我不是说这是错误的答案......我是说我不'看不到 MS 说它默认是 OneWay 的地方,但我确实相信它,因为这也是我所看到的。尽管如此,MS 应该(如果他们这样做的话更清楚)记录下来,而不是让我们相信这只是一个不错的捷径。 我同意 - 令人沮丧的是,您必须在他们论坛上的某个问题的回复中找到它。他们应该更新 MSDN 页面以反映这一点。 我将该页面标记为错误,解释了这个简单的遗漏如何花费我数天的研究时间,而如果拥有它本来可以保存所有内容。 我看到他们最终更新了文档,并评论说它是单向的,但他们仍然有代码语句本身错误,因为它没有显示模式。我再次标记了他们的文章,说明确实需要添加,因为评论还不够。他们所拥有的与他们声称的相似。【参考方案2】:

TemplateBinding 不支持双向绑定,只有 Binding 支持。即使使用 BindsTwoWayBeDefault 选项,它也不支持双向绑定。

更多信息可以在here找到,但总结一下:

但是,一个 TemplateBinding 只能 单向传输数据:从 元素的模板化父级 与 TemplateBinding。如果你需要 以相反的方式传输数据 方向或双向,绑定与 TemplatedParent 的 RelativeSource 是 你唯一的选择。例如, 与 TextBox 或 Slider 的交互 在模板内只会更改 模板化父级的属性 if 你使用双向绑定。

【讨论】:

投票支持你,因为那里找到了其他信息,但这真的应该在 MSDN 文档中,而不仅仅是一些博客,不管是谁写的。人们期望文档是最终的、最重要的,而 MSDN 错过了那个很重要的“单向”位。 @MarqueIV - 是的,我同意。但是有很多你在文档中找不到的东西,或者描述得太简单以至于没有搜索引擎会找到它;-)

以上是关于在 WPF 中,为啥 TemplateBinding 不能在 Binding 的地方工作?的主要内容,如果未能解决你的问题,请参考以下文章

为啥wpf的mainwindow中只能插入一个控件

为啥访问我的 Storyboard x:Name 在 Silverlight 中有效,但在 WPF 中无效?

为啥在 tabcontrol 内的 WPF 文本框中单击时,Windows 10 键盘会出现并立即消失?

为啥 WPF 样式在工具提示中显示验证错误适用于文本框但对组合框无效?

WPF:为啥我不应该在 ControlTemplate 中使用 TemplateBinding Margin - Margin 是不是仅适用于元素的容器?

wpf中控件全部删除后再拖控件就不能动了为啥