是否可以将以canvas为模板的itemscontrol绑定到多个DataTemplate?
我有 2 个集合,根据类型我想在画布上显示不同的控件。
我不确定,但我可以考虑一个具有 2 个 ObservableCollections 的 Viewmodel。例如,如果我有“形状”和“连接”并且我想将它们都显示在画布上?如果是图表场景...
我想以 mvvm 方式执行此操作,我不确定多个 DataTemplate 方法是否正确,但我想到了这一点。 但我仍然无法在头脑中理清绑定。如果我将 DataContext 设置为 ViewModel,似乎无法将 2 个集合绑定到项目控件... =( 我也对其他想法持开放态度......
这可能吗?如果是这样,绑定会是什么样子
您可以创建多个
ObservableCollections
,然后将您的 ItemsSource
绑定到连接这些集合的 CompositeCollection
。
然后在 XAML 中,您可以使用
DataTemplates
属性为相应类型创建不同的 DataType
,如果将其放置在资源中,则会自动应用样式。 (您还可以在 MSDN 上显示的 XAML 中创建组合,但如果应绑定 CollectionContainers
,则有点困难)
示例代码:
ObservableCollection<Employee> data1 = new ObservableCollection<Employee>(new Employee[]
{
new Employee("Hans", "Programmer"),
new Employee("Elister", "Programmer"),
new Employee("Steve", "GUI Designer"),
new Employee("Stefan", "GUI Designer"),
new Employee("Joe", "Coffee Getter"),
new Employee("Julien", "Programmer"),
});
ObservableCollection<Machine> data2 = new ObservableCollection<Machine>(new Machine[]
{
new Machine("E12", "GreedCorp"),
new Machine("E11", "GreedCorp"),
new Machine("F1-MII", "CommerceComp"),
new Machine("F2-E5", "CommerceComp")
});
CompositeCollection coll = new CompositeCollection();
coll.Add(new CollectionContainer() { Collection = data1 });
coll.Add(new CollectionContainer() { Collection = data2 });
Data = coll;
<ItemsControl ItemsSource="{Binding Data}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type local:Employee}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"/>
<TextBlock Text=" ("/>
<TextBlock Text="{Binding Occupation}"/>
<TextBlock Text=")"/>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Machine}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Model}"/>
<TextBlock Text=" - "/>
<TextBlock Text="{Binding Manufacturer}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
这里我使用不同的面板,但对于画布来说应该是相同的。
您可以在 ViewModel 中拥有
ObservableCollection<object>
并将 ItemsControl 的 Source 绑定到此集合。
然后,为了获得不同类型数据的不同外观,您可以使用两个不带 x:Key 的 DataTemplate,但在资源中正确设置了 DataType。然后 ItemsControl 将自动为您的项目选择适当的 DataTemplate。
我相信与公认的解决方案相比,有一种更简单的解决方案,尽管我在桌面应用程序中使用没有 Silverlight 的 WPF:
和之前一样使用ItemsControl,但是让它的模板使用ContentControl,可以方便地根据类型进行动态模板切换。
型号:
public class ViewModel : BindableBase
{
/*
* Other stuff not relevant to the problem
*/
public ObservableCollection<AbstractType> Properties { get; }
}
public abstract class AbstractType { }
public class ConcreteTypeP : AbstractType { }
public class ConcreteTypeQ : AbstractType { }
查看:
<UserControl>
<!--I didn't include all the namesapce/viewmodel stuff in the UserControl attributes-->
<UserControl.Resources>
<!--These can be defined in a separate file for the sake of reuse. Not exactly sure on the syntax to correctly reference them though.-->
<DataTemplate DataType="{x:Type local:ConcreteTypeP}">
<!--text blocks and whatever other stuff go here-->
</DataTemplate>
<DataTemplate DataType="{x:Type local:ConcreteTypeQ}">
<!--text blocks and whatever other stuff go here-->
</DataTemplate>
</UserControl.Resources>
<DockPanel>
<ItemsControl DockPanel.Dock="Top"
VerticalAlignment="Center"
ItemsSource="{Binding Properties}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:AbstractType}">
<ContentControl Content="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DockPanel>
隐藏代码较少的另一个选项是定义两个列表框,每个列表框都有自己的模板并绑定到自己的集合。 将它们分别定义在同一物理空间中,并根据您的状态控制哪一个可见。 您甚至可以使用视觉状态管理器和自定义状态来执行此操作。