0
votes

I am working on my own user control which derives from ItemsControl. To give a brief description of what I want to achieve here is what the XAML looks like right now:

<ItemsControl x:Class="MyApp.MyUserControl"
             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:MyApp"
             mc:Ignorable="d"
             d:DesignHeight="60" d:DesignWidth="600">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.Template>
        <ControlTemplate>
            <Grid>
                <Border Background="{TemplateBinding Background}" 
                        BorderBrush="{TemplateBinding BorderBrush}" 
                        BorderThickness="{TemplateBinding BorderThickness}">
                    <ItemsPresenter/>
                </Border>
            </Grid>
        </ControlTemplate>
    </ItemsControl.Template>
</ItemsControl>

This presents my data the way I want to, in a horizontal StackPanel, nothing fancy. In the visual tree you'll see this:

  ItemsControl
    [...Other Visual Item in The Tree...]
    ItemsPresenter
      ContentPresenter
         Item1 (ItemTemplate)
      ContentPresenter
         Item2 (ItemTemplate)

Now I would like to modify the XAML of my user control so that the tree would look like this:

  ItemsControl
    [...Other Visual Item in The Tree...]
    ItemsPresenter
      ContentPresenter
         SomeContainerDefinedInMyUserControlXAML
           Item1 (ItemTemplate)
      ContentPresenter
         SomeContainerDefinedInMyUserControlXAML
           Item2 (ItemTemplate)

The goal here is to have a wrapper container around the templated item. Its behavior would be bound to internal properties of the UserControl, allowing me to define item behaviors immune to the ItemTemplate choice made by the user of my control.

I was trying to add DataTemplates on ContentPresenter in ItemsControl.Resources, but that failed. Could someone help me out here? :)

1
The idea of templating is to provide a way to override or customize the defaults of a Control. Do you want to disallow customization of the items? You can create your own Item e.g. by extending ListBoxItem and then implement specific default behavior directly in the item instead via a template. Is this what you need? I don't think it's a good approach to expect the user of your control to be stupid. The control should be customizable to meet scenarios you hadn't in mind when designing it. This will leverage usability. It sounds you want to override user customizations. Or did I get you wrong? - BionicCode
I think you got me wrong haha. I don't expect the user of my control to be stupid (mainly because it's going to be me). My goal is NOT to remove the ability to customize the items. In fact, I expect users to be able to make their items to be whatever they want. What I want is to have a wrapper around each item, which role is going to be something that is internal to the whole user control. To give you an analogy, if you were to design a ScrollViewer, you'd want it to be customizable, but you don't want users to have to re-work the logic of how to make the scrolling happen. - MarkoPaulo

1 Answers

0
votes

You may create a derived ContentPresenter or ContentControl in the ItemControl's Get​Container​For​Item​Override method:

public class MyContainer : ContentControl
{
}

public class MyItemsControl : ItemsControl
{
    protected override DependencyObject GetContainerForItemOverride()
    {
        return new MyContainer();
    }

    protected override bool IsItemItsOwnContainerOverride(object item)
    {
        return item is MyContainer;
    }
}

I'd also suggest to move the derived ItemsControl's XAML to a default Style in Themes\Generic.xaml (as done by default for custom controls):

<Style TargetType="local:MyItemsControl">
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal"/>
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:MyItemsControl">
                <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                    <ItemsPresenter/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Also add

static MyItemsControl()
{
    DefaultStyleKeyProperty.OverrideMetadata(
        typeof(MyItemsControl),
        new FrameworkPropertyMetadata(typeof(MyItemsControl)));
}

to the control's code.