web-dev-qa-db-ja.com

後で使用するためのプレースホルダーを含むWPFユーザーコントロールを作成する方法

例を挙げて質問した方がいいでしょう。このコントロールを使用するUserControlとWindowがあるとします。

このようなコントロール(MyControlという名前)をこのような方法で設計したいと思います(これはSF構文です!):

<Grid>
  <Button>Just a button</Button>
  <PlaceHolder Name="place_holder/>
</Grid> 

そして、私のウィンドウを設計するときにそのような方法で使用します:

<MyControl/>

または

<MyControl>
  <place_holder>
    <Button>Button 1</Button>
  </place_holder>
</MyControl> 

または

<MyControl>
  <place_holder>
    <Button>Button 1</Button>
    <Button>Button 2</Button>
  </place_holder>
</MyControl> 

もちろん、WindowのMyControlにさらに多くの要素を追加できるようにしたいと思います。そのため、ある方法でコンテナーとして機能するはずです(Grid、StackPanelなど)。配置はUserControl(この例では「Just a button」ボタンの後)で定義されますが、追加するもの(要素)はWindow(UserControl-MyControl-が使用される)で定義されます。

これが私が達成したいことが明確であることを願っています。重要な点は、Windowを設計するときにXAMLを使用することです。そのため、私のクラスは他のコントロールより悪くないはずです。

さて、大きな[〜#〜] question [〜#〜]は、どのように行うのですか?

備考:スタイリングは範囲外です。私がやりたいことは、Windowを設計するときに(MyControlを設計するときではなく)MyControlにコントロールを追加することだけです。

35
greenoldman

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

ItemsControl-Version(1つの場所のコレクション用)

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

UserControlsを使用すると、内部コントロールの特定のプロパティを公開することを決定できます。 ItemsSourceのほかに、おそらくItemsControl.ItemTemplateのようなプロパティも公開したいかもしれませんが、Itemsを設定するだけで使用方法に依存します。必ずしもその必要はありません。

47
H.B.

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>

使用法:

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

enter image description here

コンテンツセクションに複数のアイテムが必要な場合は、グリッドやスタックパネルなどのコンテナーに配置するだけです。

<l:UserControl1>
    <StackPanel>
        <Button Content="Button 1" />
        <Button Content="Button 2" />
    </StackPanel>
</l:UserControl1>
22
Scott