提问人:greenoldman 提问时间:4/23/2011 最后编辑:greenoldman 更新时间:12/29/2022 访问量:36345
如何创建包含占位符供以后使用的 WPF 用户控件
How to create WPF usercontrol which contains placeholders for later usage
问:
我最好举例问这个问题。假设我有使用此控件的 UserControl 和 Window。
我想以这种方式设计这个控件(名为 MyControl)(这是科幻语法!
<Grid>
<Button>Just a button</Button>
<PlaceHolder Name="place_holder/>
</Grid>
并在设计我的窗口时以这种方式使用:
<MyControl/>
或
<MyControl>
<place_holder>
<Button>Button 1</Button>
</place_holder>
</MyControl>
或
<MyControl>
<place_holder>
<Button>Button 1</Button>
<Button>Button 2</Button>
</place_holder>
</MyControl>
当然,我希望能够在 Windows 中向 MyControl 添加更多元素。因此,在某种程度上,它应该作为容器工作(如 Grid、StackPanel 等)。位置将在 UserControl 中定义(在此示例中,在按钮“只是一个按钮”之后),但要添加的内容(哪些元素)将在 Window(其中使用 UserControl -- MyControl)中定义。
我希望这很清楚我想要实现的目标。关键点是在设计 Window 时使用 XAML,所以我的类应该不比其他控件差。
现在,最大的问题是——如何去做?
备注:样式超出范围。我所要做的就是在设计 Window 时(而不是在设计 MyControl 时)将我想要的任何控件添加到 MyControl。
答:
我认为您希望使用位于内部的 ContentPresenter 来设置 UserControl 的 ControlTemplate(以便您可以定义内容的呈现位置)。
您的自定义 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>
用法:
<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>
如果你的内容部分需要多个项目,只需将它们放在一个容器中,如网格或堆栈面板:
<l:UserControl1>
<StackPanel>
<Button Content="Button 1" />
<Button Content="Button 2" />
</StackPanel>
</l:UserControl1>
评论
ContentControls 和 ItemsControls 适用于此目的,您可以将它们绑定到 UserControl 的属性或公开它们。
使用 ContentControl(用于多个断开连接位置的占位符):
<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(用于一个位置的集合)
<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>
使用 UserControls,您可以决定公开内部控件的某些属性;此外,可能还想公开像 这样的属性,但这完全取决于你想如何使用它,如果你只是设置 那么你不一定需要任何这些。ItemsSource
ItemsControl.ItemTemplate
Items
评论
DataContext="{Binding RelativeSource={RelativeSource Self}}
不好,因为它会阻止绑定到实际数据。UserControl 将无法从其父级继承 DataContext,如果在使用控件时显式定义它,则对 PlaceHolder1 的绑定将不起作用。需要改用 RelativeSource 或 ElementName 绑定。
评论