如何创建包含占位符供以后使用的 WPF 用户控件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5758342/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 22:49:29  来源:igfitidea点击:

How to create WPF usercontrol which contains placeholders for later usage

wpfuser-controlscontainersplaceholder

提问by greenoldman

I'd better ask the question by example. Let's say I have UserControl and Window which uses this control.

我最好通过例子来问这个问题。假设我有使用此控件的 UserControl 和 Window。

I would like to design this control (named MyControl) in such way (this is sci-fi syntax!):

我想以这种方式设计这个控件(名为 MyControl)(这是科幻语法!):

<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).

当然,我希望能够在 Window 中向 MyControl 添加更多元素。因此,在某种程度上,它应该作为容器(如 Grid、StackPanel 等)工作。放置将在 UserControl 中定义(在本例中在按钮“只是一个按钮”之后),但要添加的内容(哪些元素)将在 Window 中定义(使用 UserControl -- MyControl --)。

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.

我希望这很清楚我想要实现的目标。关键是在设计Window的时候使用XAML,所以我的类应该不会比其他控件差。

Now, the big QUESTIONis -- 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).

备注:样式超出范围。我想要做的就是在设计 Window 时(而不是在设计 MyControl 时)添加我想要的任何控件到 MyControl。

回答by H.B.

ContentControls & ItemsControls are good for this, you can bind them to a property of your UserControl or expose them.

ContentControls 和 ItemsControls 对此很有用,您可以将它们绑定到 UserControl 的属性或公开它们。

Using a ContentControl (for placeholders in multiple disconnected places):

使用 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 (for collections in one place)

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>

With UserControls you can decide to expose certain properties of internal controls; besides the ItemsSourceone 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 Itemsthen you do not necessarily need any of that.

使用 UserControls,您可以决定公开内部控件的某些属性;除了ItemsSource一个人可能还想公开像 那样的属性ItemsControl.ItemTemplate,但这一切都取决于你想如何使用它,如果你只是设置了Items那么你不一定需要任何这些。

回答by Scott

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).

我认为您想使用位于内部的 ContentPresenter 设置您的 UserControl 的 ControlTemplate(以便您可以定义内容的显示位置)。

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>

enter image description here

在此处输入图片说明

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>