问题
I have a ControlTemplate for a Telerik Tile and I am overriding like below:
<ControlTemplate TargetType="{x:Type ctrl:Tile}">
<Border>
<local:UserControl>
<ContentPresenter Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}"/>
</local:UserControl>
</Border>
</ControlTemplate>
My user control looks like:
<DockPanel>
<!-- some content -->
<ContentPresenter/>
</DockPanel>
The ControlTemplate does not display the content of the UserControl.
If I change my control template to:
<ControlTemplate TargetType="{x:Type ctrl:Tile}">
<Border>
<StackPanel>
<local:UserControl/>
<ContentPresenter Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}"/>
</StackPanel>
</Border>
</ControlTemplate>
It will find the content and place it appropriately. It seems like the ControlTemplate cannot find the content once it's nested inside my UserControl. Is there anything I could be doing wrong?
Note that these ControlTemplate Items are appearing in an ItemsPresenter.
回答1:
You're treating the UserControl
as if it is a basic ContentControl
(like a Button
) which is a little different than what it actually is. Using Button
as an example, when you add a child (i.e. a TextBlock
) into a Button
element that's actually setting that TextBlock
as the Button's Content
property. The way it gets rendered is through the Button
's ControlTemplate
, which includes a ContentPresenter
to inject Content
into. The Visual Tree ends up like this:
<Button>
-start Template
<Border>
<ContentPresenter>
-start Content
<TextBlock>
So far that's basically the model your code is following. The problem is that you're using a (still ContentControl
derived) UserControl
instead, which rather than using a ControlTemplate
is most often defined with a XAML+code-behind model, where the XAML defines the Content
of the UserControl
. (It is possible to switch these models and template a UserControl
or make a Button
derived class with XAML+code-behind but not common)
If you want to both define the look of your UserControl
in XAML as normal and still be able to inject other content you can add another DependencyProperty
that mirrors the setup of the Content property and set your content to that. This approach is used with HeaderedContentControl
derivatives (i.e. Expander
) which essentially has 2 content properties, Content
and Header
. Using the new property would look like this:
<Border>
<local:UserControl>
<local:UserControl.OtherContent>
<ContentPresenter Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}"/>
</local:UserControl.OtherContent>
</local:UserControl>
</Border>
And then inside the UserControl
's XAML you need to explicitly set up the ContentPresenter
Bindings (you only get them for free inside templates of ContentControls
):
<DockPanel>
<!-- some content -->
<ContentPresenter Content="{Binding Path=OtherContent, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}"/>
</DockPanel>
If you want a ContentTemplate
, ContentTemplateSelector
, or ContentStringFormat
you'll also need to add properties and bindings for those.
来源:https://stackoverflow.com/questions/17221763/usercontrol-within-a-controltemplate