一个视图模型中使用多个数据模板的ItemsControl

30

能否将ItemsControl绑定到Canvas作为多个DataTemplates的模板?

我有两个集合,根据类型,在画布上显示不同的控件。

我想到一个ViewModel,其中有两个ObservableCollections。例如,如果我有“Shapes”和“connections”,我想要在画布上同时显示它们?在制图场景中...

我想以mvvm方式完成此操作,但我不确定使用多个DataTemplate方法是否正确,但这是我想到的方法。 但我仍然无法理清绑定关系。如果我将DataContext设置为ViewModel,对我来说似乎不可能将2个集合绑定到itemscontrol... =( 我也可以考虑其他想法....

这可行吗? 如果是,绑定会是什么样子?


你需要同时用于WPF和Silverlight吗? - Snowbear
两个都不错,但先做 WPF 更好。 - silverfighter
DataTemplateSelector 可用于 WPFSilverlight - vortexwolf
4个回答

62

您可以创建多个ObservableCollections,并将您的ItemsSource绑定到一个CompositeCollection,它可以连接这些集合。

然后在您的XAML中,可以使用DataType属性为相应类型创建不同的DataTemplates。如果将其放置在资源中,它会像样式一样自动应用。(您也可以在XAML中创建组合,该组合在MSDN上有显示,但如果应该绑定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>

我这里使用的是一个不同的面板,但对于画布(canvas)应该是相同的。


很遗憾,CompositeCollection 在 UWP 框架中不可用。 - Luca Lindholm
1
如果Employee和Machine类都继承自同一个X类,那么不需要使用CompositeCollection,只需要一个X类型的ObservableCollection即可。 - Viliam
@Viliam:当然,但这是一个主要的假设,在许多情况下都不成立。 - H.B.

5
你可以在你的ViewModel中使用ObservableCollection<object>,并将ItemsControl的Source绑定到这个集合上。
然后,为了获得不同类型数据的不同外观,你可以在资源中使用两个没有x:Key但已正确设置DataType的DataTemplates。ItemsControl将自动为你的项选择适当的DataTemplate。

2

-6

另一种代码量较少的选择是定义两个ListBox,每个ListBox都有自己的模板并绑定到自己的集合。将它们定义在同一个物理空间中,并根据状态控制哪一个可见。您甚至可以使用Visual State Manager和自定义状态来实现此操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接