【问题标题】:ContentPresenter in UserControl用户控件中的 ContentPresenter
【发布时间】:2017-06-20 02:48:54
【问题描述】:

我是 WPF 新手,我正在尝试创建一个包含一些嵌套内容的 UserControl。

<my:InformationBox Header="General Information" Width="280">
    <StackPanel>
        <Label>Label1</Label>
        <Label>Label2</Label>
    </StackPanel>
</my:InformationBox>

如您所见,我想将 StackPanel 放入其中。当我阅读一些文章时,我应该将 ContentPresenter 添加到我的 UserControl,所以我这样做了,但我找不到应该绑定到它的 Content 属性的内容。

这是我的用户控件代码

<UserControl x:Class="ITMAN.InformationBox"
             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" 
             mc:Ignorable="d" 
             d:DesignHeight="200" d:DesignWidth="280" Name="infoBox" Loaded="infoBox_Loaded">
    <StackPanel Width="{Binding ElementName=infoBox, Path=Width}" HorizontalAlignment="Stretch">
        <Label Content="{Binding ElementName=infoBox, Path=Header}" />
        <Border BorderThickness="0,1,0,0" Padding="10 5" Margin="5 0 5 10" BorderBrush="#B4CEDE">
            <StackPanel>
                <ContentPresenter Content="{Binding Content}" />
                <Label Content="End" />
            </StackPanel>
        </Border>
    </StackPanel>
</UserControl>

我从各种文章中尝试了许多组合,但我找不到任何我想要实现的工作示例。

另一个用户早些时候提出了类似的问题,但给出的答案对我没有帮助:Does anyone have a simple example of a UserControl with a single ContentPresenter?

【问题讨论】:

  • 据我所知,用户控件没有Content 属性。 ContentPresenters 通常只在模板中使用。我认为您需要做的是创建一个具有依赖属性Content 的自定义控件和一个设置控件的默认模板,就像您对用户控件所做的那样。 – 可以将 DP 添加到用户控件的类中;不过,您将不得不使用ContentControl
  • 是的,您需要将依赖属性添加到您的用户控件。看看这个codeproject.com/Articles/224230/…
  • @poke 用户控件是 ContentControl,因此 ContentPresenter 确实可用。
  • @dowhilefor 但是它不是一个内容控件,所以你可以用内容构造一个自定义的用户控件吗?生成的控件(您从中创建的控件)也是内容控件吗?
  • @poke 一个 UserControl 派生自 ContentControl。 xaml 部分是它的 ControlTemplate。因此,您可以构建根本不使用 Content 的 UserControl,但如果要使用它,则需要使用 ContentPresenter。

标签: c# wpf xaml contentpresenter


【解决方案1】:

ContentPresenter 是一种神奇的控制。如果您不向它提供任何内容,它会自动将ContentContentTemplateContentTemplateSelector 属性与TemplateBinding 设置为TemplatedParent。这意味着,您不需要向它提供任何东西,只需

<ContentPresenter/>

在您的 UserControl 中,它应该自动使用在您的 UserControl 中找到的相应属性。 还要记住像{Binding Content} 这样的绑定总是引用你的DataContext,我猜这不是你想要的。

【讨论】:

  • 我一开始就考虑过,但也没有用。我会尽量把它做成模板。
  • 好吧,我试过了,它工作得很好,也许你还有其他一些从你的问题中不清楚的需求。可以肯定的是,您可以在 xaml 中为您的用户控件命名,例如 x:Name="myControl" 并将您的内容绑定更改为 Content="{Binding ElementName=myControl, Path=Content}" 并查看是否有效。但是一个空的 ContentPresenter 在我的测试用例中有效。
  • 有趣的是,当 Im writing Content={Binding ElementName=infoBox, Path=Content}` 每次我这样做时,我的 Visual Studio 2010 都会崩溃
  • 在一个非常简单的应用程序中尝试一下。创建一个新的 wpf 项目,添加一个用户控件并在那里尝试。也许您的应用程序中还有其他问题。
【解决方案2】:

我通过将自定义样式应用到GroupBox 解决了这个问题。我在ResourceDictionary创建了Syle,如下所示

<Style x:Key="InformationBoxStyle" TargetType="GroupBox">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="GroupBox">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>
                    <Label>
                        <ContentPresenter Margin="4" ContentSource="Header"
                               RecognizesAccessKey="True" />
                    </Label>
                    <Border Grid.Row="1" BorderThickness="0,1,0,0" Padding="10 5"
                               Margin="5 0 5 10" BorderBrush="#B4CEDE">
                        <StackPanel>
                            <ContentPresenter />
                        </StackPanel>
                    </Border>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

并将此样式应用于GroupBox

<GroupBox Header="General Information" Width="280" Style="{StaticResource InformationBoxStyle}">
    <StackPanel>
        <Label>Label1</Label>
        <Label>Label2</Label>
    </StackPanel>
</GroupBox>

此代码按预期工作

您也可以参考这篇很棒的文章,其中显示了实现它的不同选项: http://www.codeproject.com/Articles/82464/How-to-Embed-Arbitrary-Content-in-a-WPF-Control 它还描述了为什么 ContentPresenter 在我的代码中不起作用。

【讨论】:

  • 该代码项目链接解释了 ContentControl 与模板静态资源而不是样式的使用效果非常好。
【解决方案3】:

您需要在您的 UserControl 代码后面创建一个依赖属性,例如 InnerContent。

    public object InnerContent
    {
        get { return GetValue(InnerContentProperty); }
        set { SetValue(InnerContentProperty, value); }
    }

    public static readonly DependencyProperty InnerContentProperty =
        DependencyProperty.Register("InnerContent", typeof(object), typeof(ConfirmationControl), new PropertyMetadata(null));

然后您需要在该 UserControl 的 XAML 端绑定到该 InnerContent。

 <ContentControl Content="{Binding InnerContent, ElementName=userControl}" />

然后,当您使用它而不是直接在 UserControl 中放置内容并覆盖现有内容时,只需将其添加到 InnerContent 部分。

    <UserControls:InformationBox>
        <UserControls:InformationBox.InnerContent>
            <TextBlock Text="I'm in the InnerContent" />
        </UserControls:InformationBox.InnerContent>
    </UserControls:InformationBox>

否则使用模板或样式也一样好,但如果您想打包用户控件以供使用,而不强迫任何人也引用样式或模板,这可能是您更好的选择之一。

【讨论】:

  • 我收到此错误消息:无法在元素“按钮”上设置名称属性值“btMain”。 “Button”在元素“MyCustomControl”的范围内,当它在另一个范围内定义时,它已经注册了一个名称。
  • @LucaZiegler 我认为这是一个新问题/问题,而不是评论。将其发布在问题中并添加代码,以便某人或我自己可以帮助您。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-02
  • 2016-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多