Since you didn't share much code, I made something out of thin air. The Idea: MyCustomControl is hosting items and for that, a ListView is used in the ControlTemplate. A default GridView is included directly in the ControlTemplate but it's possible to change it via MyCustomControl.MyView
The Custom Control:
public class MyCustomControl : ItemsControl
{
static MyCustomControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomControl), new FrameworkPropertyMetadata(typeof(MyCustomControl)));
}
public ViewBase MyView
{
get { return (ViewBase)GetValue(MyViewProperty); }
set { SetValue(MyViewProperty, value); }
}
public static readonly DependencyProperty MyViewProperty =
DependencyProperty.Register("MyView", typeof(ViewBase), typeof(MyCustomControl), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnMyViewChanged)));
private static void OnMyViewChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((MyCustomControl)d).HasCustomView = e.NewValue != null;
}
// readonly property to support the Trigger in the ControlTemplate in order to exchange the ListView.View
public bool HasCustomView
{
get { return (bool)GetValue(HasCustomViewProperty); }
private set { SetValue(HasCustomViewPropertyKey, value); }
}
private static readonly DependencyPropertyKey HasCustomViewPropertyKey =
DependencyProperty.RegisterReadOnly("HasCustomView", typeof(bool), typeof(MyCustomControl), new PropertyMetadata(false));
public static readonly DependencyProperty HasCustomViewProperty = HasCustomViewPropertyKey.DependencyProperty;
}
The Control Template (note the default GridView and the Trigger for Replacement):
<Style TargetType="{x:Type local:MyCustomControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyCustomControl}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ListView x:Name="PART_ListView"
ItemsSource="{Binding Items,RelativeSource={RelativeSource TemplatedParent}}">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="DEF"/>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="HasCustomView" Value="True">
<Setter TargetName="PART_ListView" Property="View" Value="{Binding MyView,RelativeSource={RelativeSource TemplatedParent}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Usage:
<local:MyCustomControl>
<!--uses default view-->
<TextBlock Text="Item 1"/>
<TextBlock Text="Item 2"/>
</local:MyCustomControl>
<local:MyCustomControl>
<!--uses custom view-->
<local:MyCustomControl.MyView>
<GridView>
<GridView.Columns>
<GridViewColumn Header="ABC"/>
</GridView.Columns>
</GridView>
</local:MyCustomControl.MyView>
<TextBlock Text="Item 1"/>
<TextBlock Text="Item 2"/>
</local:MyCustomControl>
Feel free to ask if anything remains unclear. As commented, I don't know how to apply your DataTemplate idea to all this stuff.
Edit:
The following is a an example with resource section to define some data and DataTemplates as well as their possible usage.
<StackPanel>
<StackPanel.Resources>
<x:Array x:Key="Items1" Type="{x:Type sys:Int32}">
<sys:Int32>1</sys:Int32>
<sys:Int32>2</sys:Int32>
<sys:Int32>3</sys:Int32>
<sys:Int32>4</sys:Int32>
</x:Array>
<x:Array x:Key="Items2" Type="{x:Type sys:Int32}">
<sys:Int32>5</sys:Int32>
<sys:Int32>4</sys:Int32>
<sys:Int32>6</sys:Int32>
<sys:Int32>7</sys:Int32>
</x:Array>
<CollectionViewSource x:Key="ItemsSource1" Source="{StaticResource Items1}"/>
<CollectionViewSource x:Key="ItemsSource2" Source="{StaticResource Items2}"/>
<DataTemplate x:Key="IntegerListTemplate1">
<local:MyCustomControl ItemsSource="{Binding}">
<!--uses default view-->
</local:MyCustomControl>
</DataTemplate>
<DataTemplate x:Key="IntegerListTemplate2">
<local:MyCustomControl ItemsSource="{Binding}">
<!--uses custom view-->
<local:MyCustomControl.MyView>
<GridView>
<GridView.Columns>
<GridViewColumn Header="ABC"/>
</GridView.Columns>
</GridView>
</local:MyCustomControl.MyView>
</local:MyCustomControl>
</DataTemplate>
</StackPanel.Resources>
<!--the default view-->
<ContentControl ContentTemplate="{StaticResource IntegerListTemplate1}" Content="{Binding Source={StaticResource ItemsSource1}}"/>
<Separator Margin="3"/>
<!--same items other view-->
<ContentControl ContentTemplate="{StaticResource IntegerListTemplate2}" Content="{Binding Source={StaticResource ItemsSource1}}"/>
<Separator Margin="3"/>
<!--different items same view as second one, no complaints about reusing-->
<ContentControl ContentTemplate="{StaticResource IntegerListTemplate2}" Content="{Binding Source={StaticResource ItemsSource2}}"/>
</StackPanel>
Edit 2, targeting the commented MCVE:
I would solve this exactly as I already explained in my first edit. Turn your control into a DataTemplate, not the view into a style.
Replace in MainWindow.xaml:
<!-- old -->
<myctrls:MyControl Grid.Row="0" Grid.Column="0" Style="{StaticResource AddressStyle}" ItemsSource="{Binding Addresses}"/>
<!-- new -->
<ContentControl Grid.Row="0" Grid.Column="0" ContentTemplate="{StaticResource AddressTemplate}" Content="{Binding Addresses}"/>
Same with the other occurences.
In MyControlStyles.xaml (or a renamed file that indicates DataTemplate usage), merge the GridView resource and the Style with the myctrls:MyControl into a DataTemplate.
Old:
<GridView x:Key="AddressGridView" x:Shared="False">
<GridViewColumn Header="City" Width="Auto" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding City}" HorizontalAlignment="Left"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Country" Width="Auto" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Country}" HorizontalAlignment="Left"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
<Style x:Key="AddressStyle" TargetType="{x:Type myctrls:MyControl}">
<Setter Property="SuggestionsView" Value="{DynamicResource AddressGridView}"/>
</Style>
New:
<DataTemplate x:Key="AddressTemplate">
<!-- the base control -->
<myctrls:MyControl ItemsSource="{Binding}">
<!-- this was previously assigned by AddressStyle -->
<myctrls:MyControl.SuggestionsView>
<!-- this was previously the AddressGridView -->
<!-- Same as before, only removed the x:Key and x:Shared -->
<GridView>
<GridViewColumn Header="City" Width="Auto" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding City}" HorizontalAlignment="Left"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Country" Width="Auto" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Country}" HorizontalAlignment="Left"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</myctrls:MyControl.SuggestionsView>
</myctrls:MyControl>
</DataTemplate>
Same procedure for the ProductsStyle.
If you don't like the ContentControl wire-up approach, consider the creation of additional viewmodels that host then collections, like AddressListViewModel. This would allow you to handle the DataTemplate by DataType instead of resource key and explicit usage in ContentControl.
ListView.Viewis of typeViewBaseso if you want to pass this part from the outside into your CustomControl, you need a property of this type. Maybe some sample code would help to understand where you want theDataTemplatein this whole thing. - grek40