none
UserControl mit Collection als ContentProperty RRS feed

  • Frage

  • Hallo zusammen,

    Ich bin gerade dabei ein ein UserControl zu programmieren, das mittels ItemsControl mehrere beliebige Controls, wie z. B. Buttons und TextBoxen, anzeigen soll. Folgenden Ansatz habe ich im Moment:

    <UserControl x:Class ... >
        <UserControl.Template>
            <ControlTemplate TargetType="UserControl">
                <ScrollViewer>
                    <ItemsControl ItemsSource="{TemplateBinding Content}">
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <StackPanel Orientation="Vertical"/>
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                    </ItemsControl>
                </ScrollViewer>
            </ControlTemplate>
        </UserControl.Template>
    </UserControl>

    So funktioniert es aktuell nicht, da ich immer den Fehler bekomme, dass die Content Eingeschaft nur einmal festgelegt werden darf. Den Aufruf stelle ich mir so vor:

    <userControls:SideMenu DockPanel.Dock="Left">
            <Label Content="Überschrift:"
                    Margin="0,10,0,5"
                    FontWeight="SemiBold"/>
            <Button Content="Button 1"
                    Height="50"
                    VerticalAlignment="Center"
                    Command="{Binding Button1Cmd}"/>
            <Button Content="Button 2"
                    Height="50"
                    VerticalAlignment="Center"
                    Command="{Binding Button2Cmd}"/>
    </userControls:SideMenu>

    Ich habe mir auch schon angeguckt, wie das in einem Panel gemacht wird, jedoch bin ich mit dem IAddChild Interface bzw. dem neueren ContentPropertyAttribut auch nicht so weit gekommen, dass ich mehrere Controls hinzufügen kann.

    Viele Grüße
    Moritz

    Montag, 22. Oktober 2018 07:37

Antworten

  • Hi Moritz,
    das UserControl erbt vom Control und da gibt es nur Content für ein einziges eingebettetes Element. Alle Steuerelemente, in die mehrere Elemente eingebettet werden können, erben vom Panel und haben dafür die Children-Eigenschaft. Die Einbettung mehrerer Elemente erfordert auch einen Ablauf zur Platzierung der einzelnen eingebetteten Elemente, der ggf. etwas komplexer sein kann. Das IAddChild ist obsolet.

    Schau Dir mal Adding children to UserControl an.


    Hier mal eine kleine Demo in C#.NET. Zuerst XAML des UserControls. Eingebettete Steuerelemente werden in ein StackPanel gepackt:

    <UserControl x:Class="WpfApp1.Window75UC1"
                 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" 
                 xmlns:local="clr-namespace:WpfApp1"
                 mc:Ignorable="d" 
                 d:DesignHeight="450" d:DesignWidth="800">
      <StackPanel x:Name="PART_Host" />
    </UserControl>

    Dazu der CodeBehind:

    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Markup;
    
    namespace WpfApp1
    {
      [ContentProperty(nameof(Children))]
      public partial class Window75UC1 : UserControl
      {
        public Window75UC1()
        {
          InitializeComponent();
          Children = PART_Host.Children;
        }
    
        public static readonly DependencyPropertyKey ChildrenProperty = DependencyProperty.RegisterReadOnly(
            nameof(Children),  // Prior to C# 6.0, replace nameof(Children) with "Children"
            typeof(UIElementCollection),
            typeof(Window75UC1),
            new PropertyMetadata());
    
        public UIElementCollection Children
        {
          get { return (UIElementCollection)GetValue(ChildrenProperty.DependencyProperty); }
          private set { SetValue(ChildrenProperty, value); }
        }
      }
    }

    Und dann der XAML des Windows, der das UserControl nutzt:

    <Window x:Class="WpfApp1.Window75"
            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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp1"
            mc:Ignorable="d"
            Title="Window75" Height="450" Width="800">
      <Grid>
        <local:Window75UC1>
          <Button Content="Befehl 1" Margin="5"/>
          <Button Content="Befehl 2" Margin="5"/>
        </local:Window75UC1>
      </Grid>
    </Window>

    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP für Developer Technologies)
    Meine Homepage mit Tipps und Tricks



    Dienstag, 23. Oktober 2018 07:02

Alle Antworten

  • Hi Moritz,
    das UserControl erbt vom Control und da gibt es nur Content für ein einziges eingebettetes Element. Alle Steuerelemente, in die mehrere Elemente eingebettet werden können, erben vom Panel und haben dafür die Children-Eigenschaft. Die Einbettung mehrerer Elemente erfordert auch einen Ablauf zur Platzierung der einzelnen eingebetteten Elemente, der ggf. etwas komplexer sein kann. Das IAddChild ist obsolet.

    Schau Dir mal Adding children to UserControl an.


    Hier mal eine kleine Demo in C#.NET. Zuerst XAML des UserControls. Eingebettete Steuerelemente werden in ein StackPanel gepackt:

    <UserControl x:Class="WpfApp1.Window75UC1"
                 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" 
                 xmlns:local="clr-namespace:WpfApp1"
                 mc:Ignorable="d" 
                 d:DesignHeight="450" d:DesignWidth="800">
      <StackPanel x:Name="PART_Host" />
    </UserControl>

    Dazu der CodeBehind:

    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Markup;
    
    namespace WpfApp1
    {
      [ContentProperty(nameof(Children))]
      public partial class Window75UC1 : UserControl
      {
        public Window75UC1()
        {
          InitializeComponent();
          Children = PART_Host.Children;
        }
    
        public static readonly DependencyPropertyKey ChildrenProperty = DependencyProperty.RegisterReadOnly(
            nameof(Children),  // Prior to C# 6.0, replace nameof(Children) with "Children"
            typeof(UIElementCollection),
            typeof(Window75UC1),
            new PropertyMetadata());
    
        public UIElementCollection Children
        {
          get { return (UIElementCollection)GetValue(ChildrenProperty.DependencyProperty); }
          private set { SetValue(ChildrenProperty, value); }
        }
      }
    }

    Und dann der XAML des Windows, der das UserControl nutzt:

    <Window x:Class="WpfApp1.Window75"
            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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp1"
            mc:Ignorable="d"
            Title="Window75" Height="450" Width="800">
      <Grid>
        <local:Window75UC1>
          <Button Content="Befehl 1" Margin="5"/>
          <Button Content="Befehl 2" Margin="5"/>
        </local:Window75UC1>
      </Grid>
    </Window>

    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP für Developer Technologies)
    Meine Homepage mit Tipps und Tricks



    Dienstag, 23. Oktober 2018 07:02
  • Hallo Peter,

    vielen Dank für den Link. Hat ohne Probleme funktioniert!

    Viele Grüße
    Moritz

    Dienstag, 23. Oktober 2018 09:26
  • Hi Moritz,
    das geht aber mit dem aktuellen Visual Studio 2017 nur in C#.NET. In VB.NET zeigt der Designer Fehler, die aber zur Laufzeit nicht stören.

    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP für Developer Technologies)
    Meine Homepage mit Tipps und Tricks

    Dienstag, 23. Oktober 2018 09:56