web-dev-qa-db-ja.com

ユーザーコントロール内でContentPresenterを使用する方法

独自のコンテンツをホストできるUserControl(この場合は、Backgroundcolorsが定義された正方形のボタン)を作成します。

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>

さて、ご想像のとおり、MainView内でこのコントロールを使用すると、コンテンツを定義するまですべてが正常に機能します。

使用:

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

この場合、「TEST」は、UserControlのコンテンツ全体(ボタンテンプレート全体)をオーバーライドします。これは、UserControl内のボタンが「コンテンツ」自体として定義されており、新しいコンテンツを定義するときにオーバーライドされるために発生すると思います。

だから最後の質問は:私が探しているものを達成することは可能ですか?はいの場合:方法は? MainViewで定義しているコンテンツを、ユーザーコントロールのContentPresenterではなく、ボタンテンプレート内の自己定義のContentPresenterに「リダイレクト」するにはどうすればよいですか?

可能であれば、コンテンツをホストする新しいdp-properyを作成したくありません。例:

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

さあ行こう。

<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>
9
Gopichandar

ContentPropertyAttributeを使用して、実際のContentプロパティの代わりにこのプロパティを設定するようにxamlに指示します。

[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); }
    }
}

次に、xamlでコンテンツプレゼンターをバインドして、代わりにInnerContentプロパティを使用します。

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

これにより、実際のコンテンツを置き換えることなく、次のことができます。

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

Youre 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>

テンプレートのTargetTypeプロパティに注意してください。これがないと、プロジェクトは正常にコンパイルされますが、ContentPresenterは機能しません。その後:

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

何かを実装する前に これを読む をお勧めします

4
Noam M

シンプル。 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>

すべてのユーザーコントロール(少なくともXAMLとそのテンプレートの用語)は、ContentPresenterが内部にあるボーダーです。 ContentPresenterだけが本当に重要な部分です。

したがって、あなたがすることは、そのテンプレートを取り出して、UserControlが持っているContentプロパティを少し異なるものにフィードすることだけです。この場合はボタンです。

これは、usercontrol out ofを他のコントロールにすることと、いくつかのコントロールintoをユーザーコントロールにすることの違いです。他のコントロールからユーザーコントロールを作成すると、はるかに強力になります。

2
Logan