1
votes

I want to create a own Usercontrol with an ItemsSource Property. I have created a UserControl "myContainer" and i have created a UserControl "myItem". Now I want to show the myItem Controls in the myContainer Control. So I declared a dependency Property ItemsSource in the myContainer Control. But if i start a testproject and bind a collection to the itemssource property nothing happend. is that the right way to implement a itemssource property?

Xaml: myContainer

<UserControl x:Class="Control.myContainer"
         ...
         x:Name="myUserControl">
<Grid>
    <DockPanel x:Name="myDockPanel">

    </DockPanel>
</Grid>

Code Behind myContainer

public partial class myContainer : UserControl, INotifyPropertyChanged
{
    public static readonly DependencyProperty ItemsSourceProperty =
            DependencyProperty.Register("ItemsSource", typeof(myItem), typeof(myContainer));

    public myContainer()
    {
        InitializeComponent();
        DataContext = this;
    }

    public ObservableCollection<myItem> ItemsSource
    {
        get
        {
            return (ObservableCollection<myItem>)GetValue(ItemsSourceProperty);
        }
        set
        {
            SetValue(ItemsSourceProperty, value);
            OnPropertyChanged("ItemsSource");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Xaml myItem

<UserControl x:Class="Control.myItem"
         ... 
         d:DesignHeight="300" d:DesignWidth="300">
<Grid>
    <Border BorderThickness="1" BorderBrush="Black" CornerRadius="2">
        <DockPanel>
            <StackPanel DockPanel.Dock="Top" Background="LightGray">
                <DockPanel Margin="2,2,2,2">
                    <Button x:Name="Button_Close" DockPanel.Dock="Right" Width="14" Height="14" Margin="5,0,0,0" VerticalAlignment="Center"></Button>
                    <Button x:Name="Button_Undock" DockPanel.Dock="Right" Width="14" Height="14" Margin="5,0,0,0" VerticalAlignment="Center"></Button>
                    <TextBlock DockPanel.Dock="Left" VerticalAlignment="Center" FontWeight="Bold" Text="{Binding Header,UpdateSourceTrigger=PropertyChanged}"></TextBlock>
                </DockPanel>
            </StackPanel>
            <ContentPresenter DockPanel.Dock="Top" ContentSource="Content"></ContentPresenter>
        </DockPanel>
    </Border>
</Grid>

CodeBehind myItem

 public partial class myItem : UserControl, INotifyPropertyChanged
{
    public static DependencyProperty _Header =
            DependencyProperty.Register("Header", typeof(String), typeof(myItem), new UIPropertyMetadata("Item"));

    public myItem()
    {
        InitializeComponent();
        DataContext = this;
    }

    public String Header
    {
        get
        {
            return (String)GetValue(_Header);
        }
        set
        {
            SetValue(_Header, value);
            OnPropertyChanged("Header");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
1
It would be far easier to derive from ListBox or ItemsControl and set the ItemsPanel property to a DockPanel. By overriding GetContainerForItemOverride you could create your own item type.Clemens
@Clemens i think this is the answer to the question instead of a commentJordy van Eijk
can you show me an example for that?user2025830
From your code it's hard to tell what exactly you're going to achieve. I guess your item shall display a header text and some other content (whatever that is). Can you provide a bit more information about what you want to? What is your item type and how shall it be visualized?Clemens
And you should know this artice: Data Templating Overview.Clemens

1 Answers

1
votes

It seems like you have an item type that basically looks like this:

public class DataItem
{
    public string Header { get; set; }
    public object Content { get; set; }
}

You may display items of this type by means of a ListBox with a DataTemplate for the items, set by the ItemTemplate property:

<ListBox ItemsSource="{Binding DataItems}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Border BorderThickness="3" BorderBrush="Aqua">
                <StackPanel Margin="10">
                    <TextBlock Text="{Binding Header}"/>
                    <ContentPresenter Content="{Binding Content}"/>
                </StackPanel>
            </Border>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

You may of course use your specialized UserControl inside the DataTemplate:

<DataTemplate>
    <Border BorderThickness="3" BorderBrush="Aqua">
        <StackPanel Margin="10">
            <TextBlock Text="{Binding Header}"/>
            <local:MyItemControl Content="{Binding Content}"/>
        </StackPanel>
    </Border>
</DataTemplate>

The default panel used by a ListBox is a VirtualizingStackPanel. If you want to use a DockPanel instead, you can achive that by setting the ItemsPanel property:

<ListBox ItemsSource="{Binding DataItems}">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <DockPanel />
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
    ...
</ListBox>

EDIT: Instead of using a DataTemplate you may also completely replace the visual appearance of a ListBoxItem by replacing its ControlTemplate in a Style in ItemsContainerStyle:

<ListBox ItemsSource="{Binding DataItems}">
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListBoxItem">
                        <Border BorderThickness="3" BorderBrush="Aqua">
                            <StackPanel Margin="10">
                                <TextBlock Text="{Binding Header}"/>
                                <ContentPresenter Content="{Binding Content}"/>
                            </StackPanel>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ListBox.ItemContainerStyle>
    ...
</ListBox>