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

gre*_*man 35 wpf user-controls containers placeholder

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

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

<Grid>
  <Button>Just a button</Button>
  <PlaceHolder Name="place_holder/>
</Grid> 
Run Code Online (Sandbox Code Playgroud)

在设计我的Window时以这种方式使用:

<MyControl/>
Run Code Online (Sandbox Code Playgroud)

要么

<MyControl>
  <place_holder>
    <Button>Button 1</Button>
  </place_holder>
</MyControl> 
Run Code Online (Sandbox Code Playgroud)

要么

<MyControl>
  <place_holder>
    <Button>Button 1</Button>
    <Button>Button 2</Button>
  </place_holder>
</MyControl> 
Run Code Online (Sandbox Code Playgroud)

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

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

现在,最大的问题是 - 如何做到这一点?

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

H.B*_*.B. 48

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>
Run Code Online (Sandbox Code Playgroud)
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();
    }
}
Run Code Online (Sandbox Code Playgroud)
<uc:MyUserControl2>
    <uc:MyUserControl2.PlaceHolder1>
        <TextBlock Text="Test"/>
    </uc:MyUserControl2.PlaceHolder1>
</uc:MyUserControl2>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)
[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();
    }
}
Run Code Online (Sandbox Code Playgroud)
<uc:MyUserControl2>
    <TextBlock Text="Test"/>
    <TextBlock Text="Test"/>
</uc:MyUserControl2>
Run Code Online (Sandbox Code Playgroud)

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

  • `DataContext ="{Binding RelativeSource = {RelativeSource Self}}`是**坏**,因为它会阻止绑定到实际数据.UserControl将无法从其父级继承DataContext,如果你定义它显式使用控件时,PlaceHolder1上的绑定将不起作用.您需要使用RelativeSource或ElementName绑定. (3认同)

Sco*_*ott 22

我想你要设置UserControl的ControlTemplate,里面有一个ContentPresenter(这样你就可以定义内容的呈现位置).

您的自定义用户控件:

<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>
Run Code Online (Sandbox Code Playgroud)

用法:

<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>
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

如果您的内容部分需要多个项目,只需将它们放在网格或堆叠面板等容器中:

<l:UserControl1>
    <StackPanel>
        <Button Content="Button 1" />
        <Button Content="Button 2" />
    </StackPanel>
</l:UserControl1>
Run Code Online (Sandbox Code Playgroud)

  • 有一个问题,你在用户控件中放置的内容是什么,例如<l:UserControl1> x </ l:UserControl>不能有命名内容.如何添加带有命名元素的内容?编译错误是无法在元素'x上设置名称属性值x.x在元素y的范围内,当在另一个范围中定义时,该元素已经注册了名称. (3认同)