How to create WPF usercontrol which contains placeholders for later usage
ContentControls & ItemsControls are good for this, you can bind them to a property of your UserControl or expose them.
Using a ContentControl (for placeholders in multiple disconnected places):
<UserControl x:Class="Test.UserControls.MyUserControl2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" Name="control"> <Grid> <Button>Just a button</Button> <ContentControl Content="{Binding PlaceHolder1, ElementName=control}"/> </Grid></UserControl>
public partial class MyUserControl2 : UserControl{ public static readonly DependencyProperty PlaceHolder1Property = DependencyProperty.Register("PlaceHolder1", typeof(object), typeof(MyUserControl2), new UIPropertyMetadata(null)); public object PlaceHolder1 { get { return (object)GetValue(PlaceHolder1Property); } set { SetValue(PlaceHolder1Property, value); } } public MyUserControl2() { InitializeComponent(); }}
<uc:MyUserControl2> <uc:MyUserControl2.PlaceHolder1> <TextBlock Text="Test"/> </uc:MyUserControl2.PlaceHolder1></uc:MyUserControl2>
ItemsControl-Version (for collections in one place)
<UserControl x:Class="Test.UserControls.MyUserControl2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" Name="control"> <Grid> <Button>Just a button</Button> <ItemsControl Name="_itemsControl" ItemsSource="{Binding ItemsSource, ElementName=control}"/> </Grid></UserControl>
[ContentProperty("Items")]public partial class MyUserControl2 : UserControl{ public static readonly DependencyProperty ItemsSourceProperty = ItemsControl.ItemsSourceProperty.AddOwner(typeof(MyUserControl2)); public IEnumerable ItemsSource { get { return (IEnumerable)GetValue(ItemsSourceProperty); } set { SetValue(ItemsSourceProperty, value); } } public ItemCollection Items { get { return _itemsControl.Items; } } public MyUserControl2() { InitializeComponent(); }}
<uc:MyUserControl2> <TextBlock Text="Test"/> <TextBlock Text="Test"/></uc:MyUserControl2>
With UserControls you can decide to expose certain properties of internal controls; besides the ItemsSource
one probably would want to also expose properties like the ItemsControl.ItemTemplate
, but it all depends on how you want to use it, if you just set the Items
then you do not necessarily need any of that.
I think you want to set your UserControl's ControlTemplate with a ContentPresenter located inside (so you can define where the Content will be presented).
Your Custom UserControl:
<UserControl x:Class="TestApp11.UserControl1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <UserControl.Template> <ControlTemplate> <StackPanel> <TextBlock Text="Custom Control Text Area 1" /> <ContentPresenter Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}" /> <TextBlock Text="Custom Control Text Area 2" /> </StackPanel> </ControlTemplate> </UserControl.Template></UserControl>
Usage:
<Window x:Class="TestApp11.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:l="clr-namespace:TestApp11" Title="Window1" Height="250" Width="200"> <StackPanel> <l:UserControl1> <Button Content="My Control's Content" /> </l:UserControl1> </StackPanel></Window>
If you need multiple items in your content section, simply place them in a container like a grid or a stackpanel:
<l:UserControl1> <StackPanel> <Button Content="Button 1" /> <Button Content="Button 2" /> </StackPanel></l:UserControl1>