简体   繁体   English

WPF TemplateBinding到模板化父级的DataContext

[英]WPF TemplateBinding to DataContext of templated parent

We have four identical popups with grids in four XAML views. 我们在四个XAML视图中有四个相同的带有网格的弹出窗口。 I'd like to move that XAML to a template and apply via a Style to to ContentControls in all four of them. 我想将XAML移至模板,然后通过样式将其应用于所有这四个控件中的ContentControls。 The trouble is passing in the source of the items in the grids. 麻烦在于传递网格中项目的来源。 We get that from each of four different view models. 我们可以从四个不同的视图模型中分别获得。 It's different in each case, the only thing that differs among the four cases. 在每种情况下都不同,唯一的不同是四种情况。 I'll probably end up renaming them consistently, but I'd like to think that's a separate issue. 我可能最终会一致地重命名它们,但是我想这是一个单独的问题。

Obviously I don't understand TemplateBinding at all. 显然我根本不了解TemplateBinding。 How do I bind a property of a child of the template to a property of the ContentControl that I'm applying the template to? 如何将模板子级的属性绑定到要将模板应用到的ContentControl的属性?

Except for the value of the DataSource attribute changing, the XAML for the grid is identical to what works perfectly well when we use it directly. 除了更改DataSource属性的值外,网格的XAML与直接使用时的效果完全一样。

I added the TextBlock just to see if I could bind anything at all. 我添加了TextBlock只是看我是否可以绑定任何东西。 I do get NaN there. 我确实在那里找到NaN

<Style x:Key="HistoryPopupContentStyle" TargetType="ContentControl">
    <Setter Property="ContentTemplate">
        <Setter.Value>
            <DataTemplate>
                <StackPanel Orientation="Vertical">
                    <TextBlock Text="{TemplateBinding Width, 
                     diag:PresentationTraceSources.TraceLevel=High}"
                               Background="White"
                               Foreground="Black"/>
                <dxg:GridControl
                    DataSource="{Binding RelativeSource={RelativeSource 
                     Path=DataContext, 
                     TraceLevel=High}"
                    VerticalAlignment="Stretch" 
                    HorizontalAlignment="Stretch" 
                    >
                        <!-- Columns. The grid displays column headers 
                                 as desired but with no rows -->
                    </dxg:GridControl.Columns>
                </dxg:GridControl>
                </StackPanel>
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>

<Popup 
    Name="PopHistory" 
    DataContext="{Binding Path=HistoryList}"
    >
    <ContentControl DataContext="{Binding Path=HistoryList}"
                    Style="{StaticResource HistoryPopupContentStyle}"
                    Name="Testing"
                    />
</Popup>

You will need to subclass ContentControl (or just Control ), so that you can add new dependency properties. 您将需要子类化ContentControl (或者只是Control ),以便可以添加新的依赖项属性。

public class GridControl : ContentControl
{
    // TODO add dependency properties

    public GridControl()
    {
        DefaultStyleKey = typeof(GridControl);
    }
}

Add your "Items" dependency property to the above control (type IEnumerable ). 将“项目”依赖项属性添加到上述控件中(类型IEnumerable )。

Next, update your template to target the new type: 接下来,更新您的模板以定位新类型:

<Style x:Key="HistoryPopupContentStyle" TargetType="local:GridControl">
    <Setter Property="ContentTemplate">
        <Setter.Value>
            <DataTemplate>
                <dxg:GridControl ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=local:GridControl},Path=Items}" />

Alternately, you could set the "Template" instead of the "ContentTemplate". 或者,您可以设置“模板”而不是“ ContentTemplate”。 This would be when you use TemplateBinding : 这将是当您使用TemplateBinding

<Style x:Key="HistoryPopupContentStyle" TargetType="local:GridControl">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:GridControl">
                <dxg:GridControl ItemsSource="{TemplateBinding Items}" />

Use it by binding the Items property to your source items: 通过将Items属性绑定到源项目来使用它:

<local:GridControl Style="{StaticResource HistoryPopupContentStyle}"
                   Items="{Binding Path=HistoryList}" />

You could also skip creating a subclass altogether, and just use the Content property of ContentControl to stash the items: 您也可以完全跳过创建子类,而仅使用ContentControlContent属性存储项:

<Style x:Key="HistoryPopupContentStyle" TargetType="ContentControl">
    <Setter Property="ContentTemplate">
        <Setter.Value>
            <DataTemplate>
                <dxg:GridControl ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=local:GridControl},Path=Content}" />

Or using the Template / TemplateBinding approach 或使用Template / TemplateBinding方法

<Style x:Key="HistoryPopupContentStyle" TargetType="ContentControl">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ContentControl">
                <dxg:GridControl ItemsSource="{TemplateBinding Content}" />

Use like this: 像这样使用:

<ContentControl Style="{StaticResource HistoryPopupContentStyle}"
                Content="{Binding Path=HistoryList}" />

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM