Question

We have four identical popups with grids in four XAML views. I'd like to move that XAML to a template and apply via a Style to to ContentControls in all four of them. 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. 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?

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.

I added the TextBlock just to see if I could bind anything at all. I do get NaN there.

<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>
Was it helpful?

Solution

You will need to subclass ContentControl (or just Control), so that you can add new dependency properties.

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

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

Add your "Items" dependency property to the above control (type 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". This would be when you use 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:

<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:

<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

<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}" />
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top