1
votes

I have created a custom control which inherits from DataGrid and adds a header property in the same way that HeaderedContentControl has a header.

[Bindable(true)]
public Object Header
{
    get { return (Object)GetValue(HeaderProperty); }
    set { SetValue(HeaderProperty, value); }
}

// Using a DependencyProperty as the backing store for Header.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty HeaderProperty =
    DependencyProperty.Register("Header", typeof(Object), typeof(ExtendedDataGrid), new PropertyMetadata(null, HeaderProperty_Changed));

private static void HeaderProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    ExtendedDataGrid ctrl = (ExtendedDataGrid)d;
    ctrl.OnHeaderChanged(e.OldValue, e.NewValue);
}

protected virtual void OnHeaderChanged(object oldValue, object newValue)
{
    RemoveLogicalChild(oldValue);
    AddLogicalChild(newValue);
}       

The control template binds a ContentPresenter content to the HeaderProperty. (This is inside the Scrollviewer ControlTemplate inside the DataGrid ControlTemplate so I can't use ContentSource)

<ContentPresenter Grid.Row="0" Grid.ColumnSpan="99"
                    Margin="0"
                    Content="{Binding Header, RelativeSource={RelativeSource AncestorType{x:Type extended:ExtendedDataGrid}}}"/>

The content is set correctly to the header property.

I have found that the content presenter does not inherit the DataGrid DataContext so I have to set the DataContext separately. This means that any bindings inside the header will not bind as expected, because the DataContext for all Elements in the header is null. I can see from the ContentPresenter implementation that it specifically sets the DataContext to null on Initialise so I understand why this is happening.

Question

However the part I do not understand and I am interested to know is how the ContentPresenter elements in many other controls correctly inherit the DataContext without (from what I can see) any different code/xaml? For example the Button ContentPresenter or the HeaderContentControl ContentPresenters.

1
In control template you have to use TemplateBinding.Sinatr
Please explain how that will help me. As I've stated the ContentPresenter is inside a ScrollViewer ControlTemplate so TemplateBinding would give me incorrect results.ndonohoe
Buttons ContentPresenter is using TemplateBinding (100% sure). I am trying to understand what you are possible asking (if it's not a binding problem) and just can't understand ;) DataContext? It can be set yes, it's inherited by Button, but it's not used in Button control template. So once again, what is your question?Sinatr
The question is about the DataContext on ContentPresenter, if you look at the default Button Style msdn.microsoft.com/en-us/library/ms753328(v=vs.110).aspx the ContentPresenter does not have either DataContext or Content set. I know that the Content is found because the default ContentSource for a ContentPresenter is Content, but I do not know how the DataContext is correctly inherited from the parent (Button in this case), yet it is not on my example ContentPresenter.ndonohoe
I found some articles addressing this topic: agsmith.wordpress.com/2008/07/14/who-set-the-datacontext and the answers to these questions: stackoverflow.com/q/12388402/138078 and stackoverflow.com/q/21767363/138078.Gerard

1 Answers

0
votes

[Sort of an anwer, because I have no idea what question I am answering ;) ]

Here is ContentPresenter of Button control template (what you see here is just an example of some possible template)

    <ContentPresenter RecognizesAccessKey="True"
        Content="{TemplateBinding ContentControl.Content}"
        ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}"
        ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}"
        Margin="{TemplateBinding Control.Padding}"
        HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}"
        VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}"
        SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />

As you can see it uses TemplateBinding. There is no DataContext in template. You do not use DataContext, nor Binding in templates.