Jak utworzyć WPF usercontrol, który zawiera symbole zastępcze do późniejszego użycia

Lepiej zadam pytanie na przykładzie. Załóżmy, że mam UserControl i Window, które używają tej kontroli.

Chciałbym zaprojektować ten kontroler (o nazwie MyControl) w taki sposób (jest to składnia sci-fi!):

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

I używać w taki sposób przy projektowaniu mojego okna:

<MyControl/>

Lub

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

Lub

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

Oczywiście chciałbym mieć możliwość dodawania jeszcze więcej elementów do MyControl w oknie. Tak więc w pewnym sensie powinien działać jako kontener (jak Grid, StackPanel, i tak dalej). Umieszczenie byłoby zdefiniowane w UserControl (w tym przykładzie po przycisku "Just a button"), ale co dodać (jakie elementy) byłoby zdefiniowane w Window(gdzie używana jest UserControl -- MyControl --).

mam nadzieję, że jest to jasne, co chciałbym osiągnąć. Kluczowym punktem jest użycie XAML przy projektowaniu okna, więc moja klasa nie powinna być gorsza od innych kontrolek.

Pytanie brzmi : jak to zrobić?

Uwagi: stylizacja jest poza zakresem. Wszystko, co chcę zrobić, to dodać wszelkie kontrolki, które chcę MyControl podczas projektowania okna (nie podczas projektowania MyControl).

Author: greenoldman, 2011-04-22

2 answers

ContentControls & ItemsControls są do tego dobre, możesz powiązać je z właściwością UserControl lub ujawnić je.

Nie jest to jednak możliwe w przypadku, gdy nie jest to możliwe.]}
<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 (dla kolekcji w jednym miejscu)

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

Z UserControls możesz zdecydować się na ujawnienie pewnych właściwości wewnętrznych kontrolek; poza {[6] } prawdopodobnie chciałbyś również ujawnić właściwości podobnie jak ItemsControl.ItemTemplate, ale wszystko zależy od tego, jak chcesz go użyć, jeśli po prostu ustawisz Items, to niekoniecznie potrzebujesz tego.

 44
Author: H.B.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-19 11:34:07

Myślę, że chcesz ustawić ControlTemplate Twojego UserControl z ContentPresenter umieszczonym wewnątrz (dzięki czemu możesz określić, gdzie zawartość będzie prezentowana).

Twój Custom UserControl:

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

Użycie:

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

Tutaj wpisz opis obrazka

Jeśli potrzebujesz kilku elementów w sekcji zawartości, po prostu umieść je w kontenerze, takim jak siatka lub stackpanel:

<l:UserControl1>
    <StackPanel>
        <Button Content="Button 1" />
        <Button Content="Button 2" />
    </StackPanel>
</l:UserControl1>
 20
Author: Scott,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-22 18:49:47