In WPF there is an element called ContentPresenter, that is often used inside control templates, as well as inside the root application markup. The concept of ContentPresenter is quite simple – it is a placeholder for any XAML content and it can be used to insert content at runtime.
What I personally find it useful for is dynamic user interface, where there is no need to define a static UI structure at design time, but at runtime there should be some components that are either defined in the application XAML or in an external resource.
A content presenter is used via the ContentPresenter element: <ContentPresenter></ContentPresenter>. The content inside this element can be partially (or completely, although its value is lost in this case) defined inside the <ContentPresenter.Content></ContentPresenter.Content> element.
If you consider using the ContentPresenter element by defining the content from scratch, there is no need to include the Content element in the base XAML – it cannot be empty and running it so will cause an exception to be thrown. Once the content is set at runtime, the proper tag will be added automatically.
Let’s take a look at an example. Here is the base XAML for a window:
<Window x:Class="WPF_Test.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="380" Width="568" Loaded="Window_Loaded"> <Grid> <ContentPresenter Name="MyContent"> </ContentPresenter> </Grid></Window>
I am also setting a name for my ContentPresenter, so that I can access it from the code-behind. I did not define any default content, but if I would want to, I would use the following XAML structure:
<ContentPresenter Name="MyContent"> <ContentPresenter.Content> <Button>Click Me</Button> </ContentPresenter.Content></ContentPresenter>
Here is some sample XAML content to test the basic capabilities:
The namespace is required here. Although you can use namespace-less elements when explicitly defining the content directly in the application, a namespace indicator is required when the content is dynamically placed.
To load the content above, in the code behind I can use this sample code:
StringReader reader = new StringReader(File.ReadAllText("D:\\Temporary\\button.txt"));XmlReader xmlReader = XmlReader.Create(reader);MyContent.Content = (Button)XamlReader.Load(xmlReader);
In this specific example, I am loading the content shown above from a text file. I am then reading it as XML (since XAML is based on XML and the formatting is preserved). The XAML data is then assigned to the Content property for the specified ContentPlaceholder.
I am parsing it via the XamlReader, that will read the elements and assign them properly. Notice the fact that I am explicitly converting the XAML content to a Button. I need to do this so that the content is correctly rendered. Otherwise, an exception will be thrown.
You might be wondering – well, with the same success you could be using a stackpanel or a grid. But this is not always the case. When control templates are built, there is a well-defined element hierarchy and sometimes using a defined container is not a choice. A content presenter can be a holder for any controls and can be bound to the content from various elements via TemplateBinding, if used in a template.