简体   繁体   English

如何在 UserControl 中使用 ContentPresenter

[英]How to use a ContentPresenter inside a UserControl

I'd like to create a UserControl (in this case a square-Button with defined Backgroundcolors) which can host it's own content.我想创建一个 UserControl(在这种情况下是一个带有定义背景颜色的方形按钮),它可以托管它自己的内容。

UserControl:用户控件:

<UserControl x:Class="SGDB.UI.Controls.ModernButton"
         xmlns:local="clr-namespace:SGDB.UI.Controls"
         xmlns:converter="clr-namespace:SGDB.UI.Converter"
         x:Name="_modernButton">
<Button>
    <Button.Resources>
        <converter:EnumToColorConverter x:Key="ColorConverter"/>
    </Button.Resources>
    <Button.Template>
        <ControlTemplate>
            <Border Width="{Binding Size, ElementName=_modernButton}" Height="{Binding Size, ElementName=_modernButton}" BorderBrush="Black" BorderThickness="0.8,0.8,3,3">
                <Grid Background="{Binding BackgroundColor, ElementName=_modernButton, Converter={StaticResource ColorConverter}}">
                    <ContentPresenter/>
                </Grid>
            </Border>
        </ControlTemplate>
    </Button.Template>
</Button>

Now, as you may expect it, if I use this Control inside my MainView everthing works just fine until I define some Content.现在,如您所料,如果我在 MainView 中使用此控件,则一切正常,直到我定义了一些内容。

Using:使用:

<control:ModernButton Size="200" BackgroundColor="Light">
    TEST
</control:ModernButton>

In this case "TEST" will override the whole Content of the UserControl (the whole Button Template).在这种情况下,“TEST”将覆盖 UserControl 的整个内容(整个按钮模板)。 I guess this happens because The Button inside the UserControl is defined as "Content" itself and it will get overridden when defining new Content.我猜这是因为 UserControl 中的 Button 本身被定义为“内容”,并且在定义新内容时它会被覆盖。

So the final question is: Is it possible to achieve what I'm looking for?所以最后一个问题是:是否有可能实现我正在寻找的东西? if yes: How?如果是:如何? How could I "redirect" the Content I'm defining in my MainView into the self-defined ContentPresenter inside my Button Template instead of the UserControls's ContentPresenter?如何将我在 MainView 中定义的内容“重定向”到我的按钮模板中的自定义 ContentPresenter 而不是 UserControls 的 ContentPresenter 中?

If possible I don't want to create a new dp-propery which hosts my Content, eg:如果可能,我不想创建一个新的 dp-propery 来托管我的内容,例如:

<controls:MordernButton Size="200" BackgroundColor="Light">
    <controls:ModernButton.Content>
        I don't want this, if possible
    </controls:ModernButton.Content>
</controls:ModernButton>

Use the ContentPropertyAttribute to instruct the xaml to set this property instead of the actual Content property.使用ContentPropertyAttribute指示 xaml 设置此属性而不是实际的 Content 属性。

[ContentProperty("InnerContent")]
public partial class ModernButton : UserControl
{
    public ModernButton()
    {
        InitializeComponent();
    }

    public static readonly DependencyProperty InnerContentProperty =
        DependencyProperty.Register("InnerContent", typeof(object), typeof(ModernButton));

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

Then in your xaml, Bind the Content Presenter to use InnerContent property instead.然后在您的 xaml 中,绑定 Content Presenter 以改用 InnerContent 属性。

<ContentPresenter Content="{Binding InnerContent, ElementName=_modernButton}"/>

This way you can do the following without replacing the actual content.这样您就可以在不替换实际内容的情况下执行以下操作。

<control:ModernButton Size="200" BackgroundColor="Light">
    TEST
</control:ModernButton>

Here we go.我们开始吧。

<UserControl x:Class="SGDB.UI.Controls.ModernButton"
     xmlns:local="clr-namespace:SGDB.UI.Controls"
     xmlns:converter="clr-namespace:SGDB.UI.Converter"
     x:Name="_modernButton">

    <UserControl.Template>
        <ControlTemplate TargetType="UserControl">
            <Button Content="{TemplateBinding Content}">
                 <Button.Resources>
                    <converter:EnumToColorConverter x:Key="ColorConverter"/>
                  </Button.Resources>
            <Button.Template >
                <ControlTemplate TargetType="Button">
                    <Border Width="{Binding Size,
                                    ElementName=_modernButton}"
                    Height="{Binding Size,
                                     ElementName=_modernButton}"
                    BorderBrush="Black"
                    BorderThickness="0.8,0.8,3,3">
                        <Grid Background="{Binding BackgroundColor, ElementName=_modernButton, Converter={StaticResource ColorConverter}}">
                            <ContentPresenter />
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Button.Template>
            </Button>
        </ControlTemplate>
    </UserControl.Template>
</UserControl>

Let's assume that youre UserControl is:让我们假设您的 UserControl 是:

<UserControl x:Class="QuickAndDirtyAttempt.Decorator" ....
      <UserControl.Template>
        <ControlTemplate TargetType="{x:Type local:Decorator}">
          <StackPanel Orientation="Vertical">
            <Label>Foo</Label>
            <ContentPresenter/>
            <Label>Bar</Label>
          </StackPanel>
        </ControlTemplate>
      </UserControl.Template>
</UserControl>

Note the TargetType property on the template: without it the project will happily compile, but the ContentPresenter will not work.请注意模板上的 TargetType 属性:如果没有它,项目将很容易编译,但 ContentPresenter 将无法工作。 And then:然后:

<Window ... >
    <StackPanel Orientation="Vertical">
        <local:Decorator>
            <Label Background="Wheat">User supplied content here</Label>
        </local:Decorator>
    </StackPanel>
</Window> 

I strongly recommend you to read this before implementing anything我强烈建议您在执行任何操作之前阅读此内容

Simple;简单; Just circumvent and replace the UserControl's Template.只需绕过并替换 UserControl 的模板。

  <UserControl.Template>
        <ControlTemplate TargetType="{x:Type UserControl}">
            <Button Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}">
                <Button.Resources>
                   <converter:EnumToColorConverter x:Key="ColorConverter"/>
                </Button.Resources>
                <Button.Template>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Border Width="{Binding Size,
                                        ElementName=_modernButton}"
                        Height="{Binding Size,
                                         ElementName=_modernButton}"
                        BorderBrush="Black"
                        BorderThickness="0.8,0.8,3,3">
                            <Grid Background="{Binding BackgroundColor, ElementName=_modernButton, Converter={StaticResource ColorConverter}}">
                                <ContentPresenter />
                            </Grid>
                        </Border>
                    </ControlTemplate>
                </Button.Template>
            </Button>
        </ControlTemplate>
    </UserControl.Template>

All a user control is (at least it terms of XAML and its template), is a Border with a ContentPresenter inside it.所有用户控件都是(至少是 XAML 及其模板的术语),是一个带有 ContentPresenter 的边框。 The ContentPresenter being the only important part, really. ContentPresenter 是唯一重要的部分,真的。

So all you do is gut out its Template and feed the Content property the UserControl has into something a little different;所以你要做的就是删除它的 Template 并将 UserControl 的 Content 属性输入一些不同的东西; in this case, your button.在这种情况下,您的按钮。

This is the difference between making a usercontrol out of other controls, and shoving some controls into a user control.这是其他控件中制作用户控件与将某些控件推用户控件之间的区别。 Making the usercontrol out of other controls gives you much more power.使用户控件脱离其他控件可为您提供更多功能。

My example for dialog box我的对话框示例

<UserControl
x:Class="CyberpunkModManager.Controls.DialogBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:CyberpunkModManager.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="450"
d:DesignWidth="800"
Foreground="{StaticResource ThemeForeground}"
mc:Ignorable="d">
<UserControl.Template>
    <ControlTemplate TargetType="UserControl">
        <Grid Background="{StaticResource ThemeTransparentColor}">
            <Border
                MinWidth="400"
                Padding="12"
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Background="{StaticResource ThemeElement}"
                CornerRadius="4">
                <ContentPresenter />
            </Border>
        </Grid>
    </ControlTemplate>
</UserControl.Template>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM