This is a mirror of official site: http://jasper-net.blogspot.com/

How to Embed Arbitrary Content in a WPF Control

| Thursday, September 20, 2012
Introduction

Many WPF controls (e.g. Button, Border, etc.) can display arbitrary XAML inside them:

<Button>any XAML here...</Button>

How do you I create my own control with this capability? So, if I write something like:

<MyControl><TextBox Text="edit me" /></MyControl>

then a text box appears inside my control? This article will demonstrate how to do it the right way, as well as a couple of wrong ways and why they are wrong.

Naive Attempt: User Controls

My first attempt was to create a user control and try to add a ContentPresenter to it. Unfortunately, that did not work, and here's why.

I added a new user control to the project, and specified the contents in its XAML file:

<UserControl x:Class="MyNamespace.MyControl" ... >
    <StackPanel Orientation="Vertical">
        <Label>Foo</Label>        
        <Label>Bar</Label>
    </StackPanel>
</UserControl> 

Then I tried to use the control in my window like this:

<Window xmlns:local="clr-namespace:MyNamespace" ...>
    <local:MyControl />
</Window> 

Everything looks OK so far. Now I was told that ContentPresenter class can show user content in custom control, so I put it in the XAML definition for my user control:

<!-- don't do this at home --> 
<!-- MyControl.xaml --> 
<UserControl x:Class="MyNamespace.MyControl" ... >
    <StackPanel Orientation="Vertical">
        <Label>Foo</Label>        
        <ContentPresenter />
        <Label>Bar</Label>
    </StackPanel>
</UserControl>
...
<!-- MyWindow.xaml --> 
<Window xmlns:local="clr-namespace:MyNamespace" ...>
    <local:MyControl>User supplied content here</local:MyControl>
</Window> 

It does not work, because we end up defining user control's Content property twice: once inside the user control XAML, and once inside Window XAML. Window XAML wins this battle, and the only thing you will see is the text User supplied content here. Neither Foo, nor Bar are shown, and ContentPresenter has no effect.

Quick and Dirty Attempt

It turns out that ContentPresenter works only inside a <ControlTemplate>. So, I created a QuickAndDirtyAttempt project with a Decorator control there (yes, I know, WPF already has a Decorator type, but I could not come up with a better name). To achieve our goals in a brute-force kind of way, I just assign a control template to the user control. Contrary to this MSDN article, it is possible to apply a control template to a user control.

<UserControl x:Class="QuickAndDirtyAttempt.Decorator" ...=""
  <UserControl.Template>
    <ControlTemplate TargetType="{x:Type local:Decorator}">
      <StackPanel Orientation="Vertical">
        <Label>Foo</Label>
        <ContentPresenter />
        <Label>Bar</Label>
      </StackPanel>
    </ControlTemplate>
  </UserControl.Template>
</UserControl>

Note the TargetType property on the template: without it the project will happily compile, but the ContentPresenter will not work.

<Window ... >
    <StackPanel Orientation="Vertical">
        <local:Decorator>
            <Label Background="Wheat">User supplied content here</Label>
        </local:Decorator>
    </StackPanel>
</Window> 

Read more: Codeproject
QR: Inline image 1

Posted via email from Jasper-net

0 comments: