具有多个数据模板的 ItemsControl
ItemsControl with multiple DataTemplates
我有一个带有 Canvas 作为 ItemsPanelTemplate
和多个 DataTemplates
的 ItemsControl:
<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>
两个视图模型位置 (X,Y) 绑定到 Canvas 左侧和顶部 属性。问题是我想以不同的方式将 viewModels 属性绑定到 Canvas。
例如 Object1ViewModel
使用 MultiBinding 转换器,returns 一个值取决于 ItemControl 的大小等因素,其中 Object2ViewModel
应该直接绑定到 Canvas Left/Top 如上所示的属性。
我尝试直接在 DataTemplate 中设置绑定,这样我就可以为不同的 DataTemplate 使用不同的绑定样式,但这不起作用。对象将无法按原样找到 Canvas在 ContentPresenter 中创建。
听起来你需要 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;
}
}
或者类似的东西。
所以我根据 Clemens 的评论弄明白了。正如他提到的,我需要一个 ItemContainerStyleSelector,所以我制作了 class 可以给我合适的样式:
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;
}
}
在 xaml 中,我将在资源中定义样式并将 ItemContainerStyleSelector
设置为我的新样式选择器:
<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>
执行此操作时,不得设置 属性 ItemContainerStyle
,否则样式选择器将被忽略。
我有一个带有 Canvas 作为 ItemsPanelTemplate
和多个 DataTemplates
的 ItemsControl:
<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>
两个视图模型位置 (X,Y) 绑定到 Canvas 左侧和顶部 属性。问题是我想以不同的方式将 viewModels 属性绑定到 Canvas。
例如 Object1ViewModel
使用 MultiBinding 转换器,returns 一个值取决于 ItemControl 的大小等因素,其中 Object2ViewModel
应该直接绑定到 Canvas Left/Top 如上所示的属性。
我尝试直接在 DataTemplate 中设置绑定,这样我就可以为不同的 DataTemplate 使用不同的绑定样式,但这不起作用。对象将无法按原样找到 Canvas在 ContentPresenter 中创建。
听起来你需要 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;
}
}
或者类似的东西。
所以我根据 Clemens 的评论弄明白了。正如他提到的,我需要一个 ItemContainerStyleSelector,所以我制作了 class 可以给我合适的样式:
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;
}
}
在 xaml 中,我将在资源中定义样式并将 ItemContainerStyleSelector
设置为我的新样式选择器:
<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>
执行此操作时,不得设置 属性 ItemContainerStyle
,否则样式选择器将被忽略。