如何创建包含占位符以供以后使用的 WPF 用户控件 [英] How to create WPF usercontrol which contains placeholders for later usage
问题描述
我最好通过例子来提问.假设我有使用此控件的 UserControl 和 Window.
我想以这种方式设计这个控件(名为 MyControl)(这是科幻语法!):
<按钮>只是一个按钮</按钮><PlaceHolder 名称="place_holder/></网格>
并在设计我的窗口时以这种方式使用:
<MyControl/>
或
<MyControl><占位符><按钮>按钮 1</按钮></place_holder></我的控制>
或
<MyControl><占位符><按钮>按钮 1</按钮><按钮>按钮 2</按钮></place_holder></我的控制>
当然,我希望能够在 Window 中向 MyControl 添加更多元素.因此,在某种程度上,它应该作为容器工作(如 Grid、StackPanel 等).位置将在 UserControl 中定义(在此示例中,在按钮只是一个按钮"之后),但要添加的内容(哪些元素)将在 Window 中定义(使用 UserControl -- MyControl --).
我希望这很清楚我想要实现的目标.重点是在设计Window的时候使用XAML,所以我的类应该不会比其他控件差.
现在,最大的问题是——怎么做?
备注:样式超出范围.我要做的就是在设计 Window 时(而不是在设计 MyControl 时)将我想要的任何控件添加到 MyControl.
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"名称="控制"><网格><按钮>只是一个按钮</按钮><ContentControl Content="{绑定 PlaceHolder1, ElementName=control}"/></网格></用户控制>
公共部分类 MyUserControl2 : UserControl{公共静态只读 DependencyProperty PlaceHolder1Property =DependencyProperty.Register("PlaceHolder1", typeof(object), typeof(MyUserControl2), new UIPropertyMetadata(null));公共对象 PlaceHolder1{获取{返回(对象)GetValue(PlaceHolder1Property);}设置 { SetValue(PlaceHolder1Property,值);}}公共 MyUserControl2(){初始化组件();}}
<uc:MyUserControl2><uc:MyUserControl2.PlaceHolder1><TextBlock 文本="测试"/></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"名称="控制"><网格><按钮>只是一个按钮</按钮><ItemsControl Name="_itemsControl" ItemsSource="{Binding ItemsSource, ElementName=control}"/></网格></用户控制>
[ContentProperty("Items")]公共部分类 MyUserControl2:UserControl{公共静态只读 DependencyProperty ItemsSourceProperty =ItemsControl.ItemsSourceProperty.AddOwner(typeof(MyUserControl2));公共 IEnumerable ItemsSource{获取 { 返回 (IEnumerable)GetValue(ItemsSourceProperty);}设置 { SetValue(ItemsSourceProperty, value);}}公共 ItemCollection 项目{得到 { 返回 _itemsControl.Items;}}公共 MyUserControl2(){初始化组件();}}
<uc:MyUserControl2><TextBlock 文本="测试"/><TextBlock 文本="测试"/></uc:MyUserControl2>
使用 UserControls,您可以决定公开内部控件的某些属性;除了 ItemsSource
之外,可能还想公开 ItemsControl.ItemTemplate
之类的属性,但这一切都取决于你想如何使用它,如果你只是设置 >Items
那么你就不一定需要这些了.</p>
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.
这篇关于如何创建包含占位符以供以后使用的 WPF 用户控件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!