如何从ContentTemplate绑定到周围的自定义控件? [英] How to bind from a ContentTemplate to the surrounding custom Control?
问题描述
我具有以下用户控件:
<TabItem
x:Name="Self"
x:Class="App.MyTabItem"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:app="clr-namespace:App"
>
<TabItem.Header>
<!-- This works -->
<TextBlock Text="{Binding ElementName=Self, Path=ShortLabel, UpdateSourceTrigger=PropertyChanged}"/>
</TabItem.Header>
<TabItem.ContentTemplate>
<DataTemplate>
<!-- This binds to "Self" in the surrounding window's namespace -->
<TextBlock Text="{Binding ElementName=Self, Path=ShortLabel, UpdateSourceTrigger=PropertyChanged}"/>
此自定义TabItem定义了一个DependencyProperty
'ShortLabel'来实现一个接口.我想从TabItem
的DataTemplate
绑定到此属性和其他属性.但是由于奇怪的交互作用,DataTemplate
中的TextBlock
绑定到TabItem
的父容器,该容器也称为"Self",但在另一个Xaml文件中定义./p>
问题
为什么绑定不能在TabItem.Header中工作,而不能在TabItem.ContentTemplate内部工作?我该如何继续从DataTemplate进入用户控件的属性?
我已经尝试过的东西
-
TemplateBinding
:尝试绑定到TabItem
内胆中的ContentPresenter. -
FindAncestor, AncestorType={x:Type TabItem}
:找不到TabItem
父对象.当我指定MyTabItem
类型时,这也不起作用. -
ElementName=Self
:尝试在错误的范围(父容器,而不是TabItem
)中绑定到具有该名称的控件.我认为这提示了为什么它不起作用:DataTemplate不是在XAML中定义的位置创建的,而是显然由父容器创建的.
我假设我可以替换整个ControlTemplate
以达到所需的效果,但是由于我想保留TabItem
的默认外观,而不必维护整个ControlTemplate
,因此我非常不愿意这样做.
编辑
同时我发现问题是:如果ItemsSource
包含Visual
,则TabControl
不能有(任何)ItemsTemplate
(包括DisplayMemberPath
).在MSDN上有一个线程论坛解释原因.
由于这似乎是WPF的TabControl的基本问题,所以我要结束这个问题.感谢您的所有帮助!
问题似乎是您在使用ContentTemplate而不实际使用content属性. ContentTemplate的DataTemplate的默认DataContext是TabItem的Content属性.但是,我所说的内容都没有真正解释为什么绑定不起作用.不幸的是,我无法给出确切的答案,但是我最大的猜测是,由于TabControl重用ContentPresenter来显示所有选项卡项目的content属性.
因此,在您的情况下,我将代码更改为如下所示:
<TabItem
x:Class="App.MyTabItem"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:app="clr-namespace:App"
Header="{Binding ShortLabel, RelativeSource={RelativeSource Self}}"
Content="{Binding ShortLabel, RelativeSource={RelativeSource Self}}" />
如果ShortLabel是一个更复杂的对象,而不仅仅是一个字符串,那么您想引入一个ContentTemplate:
<TabItem
x:Class="App.MyTabItem"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:app="clr-namespace:App"
Header="{Binding ShortLabel, RelativeSource={RelativeSource Self}}"
Content="{Binding ComplexShortLabel, RelativeSource={RelativeSource Self}}">
<TabItem.ContentTemplate>
<DataTemplate TargetType="{x:Type ComplexType}">
<TextBlock Text="{Binding Property}" />
</DataTemplate>
</TabItem.ContentTemplate>
</TabItem>
I've got the following user control:
<TabItem
x:Name="Self"
x:Class="App.MyTabItem"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:app="clr-namespace:App"
>
<TabItem.Header>
<!-- This works -->
<TextBlock Text="{Binding ElementName=Self, Path=ShortLabel, UpdateSourceTrigger=PropertyChanged}"/>
</TabItem.Header>
<TabItem.ContentTemplate>
<DataTemplate>
<!-- This binds to "Self" in the surrounding window's namespace -->
<TextBlock Text="{Binding ElementName=Self, Path=ShortLabel, UpdateSourceTrigger=PropertyChanged}"/>
This custom TabItem defines a DependencyProperty
'ShortLabel' to implement an interface. I would like to bind to this and other properties from within the TabItem
's DataTemplate
. But due to strange interactions, the TextBlock
within the DataTemplate
gets bound to the parent container of the TabItem
, which also is called "Self", but defined in another Xaml file.
Question
Why does the Binding work in the TabItem.Header, but not from within TabItem.ContentTemplate, and how should I proceed to get to the user control's properties from within the DataTemplate?
What I already tried
TemplateBinding
: Tries to bind to the ContentPresenter within the guts of theTabItem
.FindAncestor, AncestorType={x:Type TabItem}
: Doesn't find theTabItem
parent. This doesn't work either, when I specify theMyTabItem
type.ElementName=Self
: Tries to bind to a control with that name in the wrong scope (parent container, notTabItem
). I think that gives a hint, why this isn't working: the DataTemplate is not created at the point where it is defined in XAML, but apparently by the parent container.
I assume I could replace the whole ControlTemplate
to achieve the effect I'm looking for, but since I want to preserve the default look and feel of the TabItem
without having to maintain the whole ControlTemplate
, I'm very reluctant to do so.
Edit
Meanwhile I have found out that the problem is: TabControl
s can't have (any) ItemsTemplate
(that includes the DisplayMemberPath
) if the ItemsSource
contains Visual
s. There a thread on MSDN Forum explaining why.
Since this seems to be a fundamental issue with WPF's TabControl, I'm closing the question. Thanks for all your help!
What appears to be the problem is that you are using a ContentTemplate without actualy using the content property. The default DataContext for the ContentTemplate's DataTemplate is the Content property of TabItem. However, none of what I said actually explains why the binding doesn't work. Unfortunately I can't give you a definitive answer, but my best guess is that it is due to the fact that the TabControl reuses a ContentPresenter to display the content property for all tab items.
So, in your case I would change the code to look something like this:
<TabItem
x:Class="App.MyTabItem"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:app="clr-namespace:App"
Header="{Binding ShortLabel, RelativeSource={RelativeSource Self}}"
Content="{Binding ShortLabel, RelativeSource={RelativeSource Self}}" />
If ShortLabel is a more complex object and not just a string then you would want to indroduce a ContentTemplate:
<TabItem
x:Class="App.MyTabItem"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:app="clr-namespace:App"
Header="{Binding ShortLabel, RelativeSource={RelativeSource Self}}"
Content="{Binding ComplexShortLabel, RelativeSource={RelativeSource Self}}">
<TabItem.ContentTemplate>
<DataTemplate TargetType="{x:Type ComplexType}">
<TextBlock Text="{Binding Property}" />
</DataTemplate>
</TabItem.ContentTemplate>
</TabItem>
这篇关于如何从ContentTemplate绑定到周围的自定义控件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!