I'd better ask the question by example. Let's say I have UserControl and Window which uses this control.
I would like to design this control (named MyControl) in such way (this is sci-fi syntax!):
<Grid>
<Button>Just a button</Button>
<PlaceHolder Name="place_holder/>
</Grid>
and use in such ways when designing my Window:
<MyControl/>
or
<MyControl>
<place_holder>
<Button>Button 1</Button>
</place_holder>
</MyControl>
or
<MyControl>
<place_holder>
<Button>Button 1</Button>
<Button>Button 2</Button>
</place_holder>
</MyControl>
Of course I would like to have ability to add even more elements to MyControl in Window. So, in a way it should work as container (like Grid, StackPanel, and so on). The placement would be defined in UserControl (in this example after button "Just a button") but what to add (what elements) would be defined in Window (where UserControl -- MyControl -- is used).
I hope this is clear what I would like to achieve. The key point is using XAML when designing Window, so my class should be no worse than other controls.
Now, the big QUESTION is -- how to do it?
Remarks: styling is out of scope. All I want to do is add any controls I want to MyControl when designing Window (not when designing MyControl).
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With