如何从ContentTemplate绑定到周围的自定义控件? [英] How to bind from a ContentTemplate to the surrounding custom Control?

查看:158
本文介绍了如何从ContentTemplate绑定到周围的自定义控件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我具有以下用户控件:

<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'来实现一个接口.我想从TabItemDataTemplate绑定到此属性和其他属性.但是由于奇怪的交互作用,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 the TabItem.
  • FindAncestor, AncestorType={x:Type TabItem}: Doesn't find the TabItem parent. This doesn't work either, when I specify the MyTabItem type.
  • ElementName=Self: Tries to bind to a control with that name in the wrong scope (parent container, not TabItem). 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: TabControls can't have (any) ItemsTemplate (that includes the DisplayMemberPath) if the ItemsSource contains Visuals. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆