Reputation: 2711
I have a ItemsControl with a Canvas as ItemsPanelTemplate
and multiple DataTemplates
like this:
<ItemsControl ItemsSource="{Binding Path=DisplayObjects}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type viewModels:Object1ViewModel}">
<views:Object1UIElement/>
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:Object2ViewModel}">
<viewModels:Object2UIElement/>
</DataTemplate>
</ItemsControl.Resources >
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding Path=X"/>
<Setter Property="Canvas.Top" Value="{Binding Path=Y"/>
<!-- Serveral more properties that are either attached to the Canvas or UIElement -->
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
The two viewmodels location (X,Y) is bonded to the Canvas Left and Top property. The problem is that I want to bind the viewModels properties to the Canvas in different ways.
For example Object1ViewModel
use a MultiBinding converter that returns a value depending on factors like the size of the ItemControl, where Object2ViewModel
should bind directly to the Canvas Left/Top properties like shown above.
I have tried to set the binding directly in the DataTemplate so I can have different binding styles for different DataTemplates but that does not work.. The objects will not be able to find the Canvas as they are created in a ContentPresenter.
Upvotes: 1
Views: 2900
Reputation: 2711
So I figured it out with the comment from Clemens. As he mentioned I needed a ItemContainerStyleSelector so I made the class that would give me the appropriate style:
public class MyItemContainerStyleSelector : StyleSelector
{
public override Style SelectStyle(object item, DependencyObject container)
{
var element = container as FrameworkElement; // this will be a ContentPresenter
if (element == null) return null;
var viewModel = element.DataContext;
if (viewModel is Object1ViewModel)
{
return element.FindResource("Object1Style") as Style;
}
if (viewModel is Object2ViewModel)
{
return element.FindResource("Object2Style") as Style;
}
return null;
}
}
In xaml I would define the styles in the resources and set ItemContainerStyleSelector
to my new style selector:
<UserControl.Resources>
<utilities:MyItemContainerStyleSelector x:Key="MyStyleSelector"/>
<Style x:Key="Object1Style" TargetType="ContentPresenter">
...
</Style>
<Style x:Key="Object2Style" TargetType="ContentPresenter">
...
</Style>
</UserControl.Resources>
<ItemsControl
...
ItemContainerStyleSelector="{StaticResource MyStyleSelector}" >
</ItemsControl>
When doing this the property ItemContainerStyle
must not be set or the style selector will be ignored.
Upvotes: 2
Reputation: 7004
Sounds like you need a DataTemplateSelector?
public class MyWonderfulTemplateSelector : DataTemplateSelector
{
public override DataTemplate
SelectTemplate(object item, DependencyObject container)
{
FrameworkElement element = container as FrameworkElement;
if (element != Object1ViewModel)
{
return element.FindResource("DataTemplate1") as DataTemplate;
} else if (element != Object2ViewModel) {
return element.FindResource("DataTemplate2") as DataTemplate;
}
return null;
}
}
Or something along those lines.
Upvotes: 0