ItemsControl с несколькими DataTemplates для viewmodel

Можно ли связать элемент управления с холстом в качестве шаблона с несколькими DataTemplates?

У меня есть 2 коллекции и в зависимости от типа, который я хотел бы отобразить на моем холсте другого элемента управления.

Я не уверен, но я мог подумать о Viewmodel, который имеет 2 ObservableCollections. Например, если бы у меня были "Shapes" и "connections", и я хотел бы отображать их как на холсте? В случае сценария диаграммы...

Я хотел бы сделать это в mvvm-манере, и я не уверен, правильный подход к DataTemplate верен, но это мне пришло в голову. Но у меня все еще есть проблемы, чтобы получить привязку прямо в моей голове. Если я установил DataContext для ViewModel для меня, кажется невозможным привязать 2 коллекции к элементу управления... = ( Я также открыт для других идей...

Возможно ли это? И если да, как бы привязка выглядела как

Ответ 1

Вы можете создать несколько ObservableCollections, а затем привязать ItemsSource к CompositeCollection, который объединяет эти коллекции.

Затем в вашем XAML вы можете создать разные DataTemplates для соответствующих типов, используя свойство DataType, которое подобно стилям автоматически применяется, если оно помещено в ресурсы. (Вы также можете создать композит в 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>

Здесь я использую другую панель, но она должна быть одинаковой для холста.

Ответ 2

У вас может быть ObservableCollection<object> в вашей модели ViewModel и привязать источник ItemsControl к этой коллекции.

Затем, чтобы разглядеть разные типы данных, вы могли бы использовать два DataTemplates без x: Key, но с правильным набором DataType в своих ресурсах. Затем ItemControl автоматически выберет соответствующий DataTemplate для вашего элемента.

Ответ 3

Посмотрите на селектор шаблонов данных: здесь или здесь.

Ответ 4

Другим вариантом с меньшим количеством кода будет определение двух ListBoxes, каждый из которых имеет свои собственные шаблоны и привязан к их собственным коллекциям. Определите их каждый в одном и том же физическом пространстве и просто контролируйте, какой из них отображается на основе вашего состояния. Вы даже можете сделать это с помощью диспетчера визуальных состояний и пользовательских состояний.