WPF - 在UserControl内托管内容

70
我正在尝试创建一个带有两行Grid的用户控件,第一行用于标题,第二行用于内容,该内容将在用户控件外部定义,例如我们示例中的Button
但是,我无法让它起作用。
UserControl1 xaml:
  <Grid Background="LightBlue">
    <Grid.RowDefinitions>
        <RowDefinition Height="50" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <TextBlock Text="Title" FontSize="30" Margin="10,0,0,0"/>
</Grid>

MainWindow.xaml:

 <Grid>
    <local:UserControl1>
        <Button>Click me</Button>
    </local:UserControl1>
</Grid>

下面的图片应该能够解释我的问题:

在这里输入图片描述
5个回答

87

以下代码

<local:UserControl1>
    <Button>Click me</Button>
</local:UserControl1>

这意味着您将UserControl1的Content属性设置为该按钮。此按钮仅替换了UserControls1的标记。因此,您在UserControl1.xaml中拥有的所有内容都不再存在。

编辑

如果您希望您的UserControl承载一些将在其外部设置的标记,可以向其添加一个DependencyProperty,例如:

    /// <summary>
    /// Gets or sets additional content for the UserControl
    /// </summary>
    public object AdditionalContent
    {
        get { return (object)GetValue(AdditionalContentProperty); }
        set { SetValue(AdditionalContentProperty, value); }
    }
    public static readonly DependencyProperty AdditionalContentProperty =
        DependencyProperty.Register("AdditionalContent", typeof(object), typeof(UserControl1),
          new PropertyMetadata(null));

并添加一些元素到它的标记中以承载额外的内容。以下是一个扩展你提供的标记的示例:


<UserControl ... Name="userControl">
    <Grid Background="LightBlue">
        <Grid.RowDefinitions>
            <RowDefinition Height="50" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <TextBlock Text="Title" FontSize="30" Margin="10,0,0,0"/>
        <ContentPresenter Content="{Binding AdditionalContent, ElementName=userControl}" />
    </Grid>
</UserControl>

现在您可以按照以下方式使用它:

<local:UserControl1>
    <local:UserControl1.AdditionalContent>
        <Button>Click me</Button>
    </local:UserControl1.AdditionalContent>
</local:UserControl1>

1
为什么要使用额外的依赖属性,而不是仅替换控件模板并绑定到内容属性? - codekaizen
45
可以使用类上的[ContentProperty("AdditionalContent")]属性来替代使用 <local:UserControl1.AdditionalContent>,这样就可以让自定义控件在控件的内容中直接嵌套。这很棒,因为这样就不会有人在意外设置内容时破坏它,而应该设置 AdditionalContent - Ondrej Janacek
看一下blindmeis的回答。你可以使用TemplateBinding来设置ContentPresenter的Content、FontSize等。 - EvAlex
@OndrejJanacek 那真的应该是被接受的答案。它优雅地避免了一些在这里建议的变通方法中的所有陷阱。 - Gusdor
3
CalibrationPoint是什么?智能感知无法找到该类的可能解决方案,它是一些自定义的东西吗?[[编辑]]对不起,我没有检查Register方法的参数。我认为这应该更改为UserControl1编译。 - Bishoy
显示剩余5条评论

31
你需要设置 ControlTemplate
<UserControl>
<UserControl.Resources>
    <Style TargetType="{x:Type local:UserControl1}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:UserControl1}">
                    <Grid Background="LightBlue">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="50" />
                            <RowDefinition Height="*" />
                        </Grid.RowDefinitions>
                        <TextBlock Grid.Row="0" Text="Title" FontSize="30" Margin="10,0,0,0"/>
                        <ContentPresenter Grid.Row="1" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</UserControl.Resources>
</UserControl>

11
为什么您要通过 UserControl.Resources/Style 来设置它,而不是将 ControlTemplate 直接作为 UserControl.Template 的内容? - LWChris
1
不幸的是,似乎不支持设置UserControlTemplate属性:https://social.msdn.microsoft.com/forums/silverlight/en-US/a41ff344-1760-4e2d-afc2-67307372b584/how-can-set-usercontrols-template-in-xaml - James Ko
2
UserControl.Template 对我有效。我使用 TargetType="{x:Type UserControl}"。 - Der_Meister
1
谢谢您。 - Krythic
1
设置控件模板会禁用您在任何设置的内容中使用 x:Name。在一个 .Net 4.7 WPF 应用程序中进行了测试。Namescope 已经设置好了。 - Gusdor

10

你可以对用户控件进行模板化,以添加其他可视元素,例如TextBlock

<UserControl>
<UserControl.Style>
  <Style TargetType="{x:Type UserControl}">
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate>              
          <Grid Background="LightBlue"> 
          <Grid.RowDefinitions> 
            <RowDefinition Height="50" /> 
            <RowDefinition Height="*" /> 
          </Grid.RowDefinitions> 
          <TextBlock Text="Title" FontSize="30" Margin="10,0,0,0"/> 
          <ContentPresenter Grid.Row="1" Content="{TemplateBinding Content}"  />
          </Grid> 
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
</UserControl.Style>
<Button>
  Click me!
</Button>
</UserControl>

1
使用 <ControlTemplate TargetType="{x:Type UserControl}"> 可以在资源字典中使其正常工作。 - Jinjinov
我创建了一个新的UserControl,需要包含内容。 这似乎是唯一的解决方案,在实现过程中或以后不会引起大量其他问题。例如,@blindmeis的解决方案在控件本身的设计器中没有显示任何可视化内容。只有在使用新控件的控件的设计器中才能看到。 仍然存在一个问题,即设置为新控件内容的控件不能具有名称属性。 - Rumble

9

使用模板与

<ContentControl/>

代替使用内容呈现器

因此,请将此放置在:

<UserControl.Style>
        <Style TargetType="{x:Type UserControl}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type UserControl}" >
                          <Grid Background="LightBlue"> 
                           <Grid.RowDefinitions> 
                            <RowDefinition Height="50" /> 
                            <RowDefinition Height="*" /> 
                          </Grid.RowDefinitions> 
                           <TextBlock Text="Title" FontSize="30" Margin="10,0,0,0"/> 

                        <ContentControl  Grid.Row="1" Content="{TemplateBinding Content}"  />

                        </Grid> 
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </UserControl.Style>

到您的用户控件


3
为什么要使用带有ContentControl的模板而不是使用ContentPresenter? - Crono
3
最好在模板中使用ContentPresenter,参见https://dev59.com/Y3M_5IYBdhLWcg3wp06l#1288353。 - Der_Meister

2
这是一个用户控件的简单通用模板(不使用样式或属性设置内容):
<UserControl ...>
   <UserControl.Template>
       <ControlTemplate TargetType="{x:Type UserControl}">
           <!-- control contents here -->
           <ContentPresenter/><!-- outside contents go here -->
           <!-- control contents here -->
       </ControlTemplate>
   </UserControl.Template>
</UserControl>
< p > <ControlTemplate>代表每个控件的XAML副本。

当使用控件时,<ContentPresenter>是放置Content的位置。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接