Reputation: 14153
I am developing an application in WPF using the MVVM pattern and have come across something that may be a bit unique.
I have an abstract class MapEntity
which represents an entity that can be displayed on a drawing surface of my application. Other classes such as LineEntity
, TextEntity
, etc, etc, inherit from MapEntity
.
To display these, I create an ObservableCollection
for each type and bind it to my XAML which takes the properties of each entity and displays them. (For example, creates a textbox with the color and text of a TextEntity
)
Managing these entities together feels like a bit of a hack. If I have a bunch of collections for each entity, I could just create an ObservableCollection<MapEntity>
, and add all of the entities to it. This would make handling them easier, such as checking their bounds when a user drags an entity, or updating them via their update method defined in MapEntity
. Standard inheritance stuff.
The problem comes when using this technique, is there a way to create an ItemsControl
that is binded to this single collection (Rather than having each ItemsControl
binded to a collection of TextEntity
, LineEntity
, etc), yet only displays elements of a certain type?
For example:
ViewModel:
public ObvervableCollection<MapEntity> Entities { get; set; //OnPropertyChanged stuff}
...
Entities.Add(new LineEntity(...));
Entities.Add(new TextEntity(...));
So, I am adding different MapEntities
to a single collection rather than multiple ones for each type.
View:
Using separate collections, I could bind each ItemsControl
of items to a specific collection, but using one Entities
collection, I can not find a way to "filter" elements of a certain type derived from MapEntity
.
So instead of doing:
<ItemsControl ItemsSource="{Binding LineEntities}"> <!-- More Stuff --> </ItemsControl>
<ItemsControl ItemsSource="{Binding TextEntities}"> <!-- More Stuff --> </ItemsControl>
I want to do:
<ItemsControl ItemsSource="{Binding Entities WHERE type = LineEntity}"> <!-- More Stuff --> </ItemsControl>
<ItemsControl ItemsSource="{Binding Entities WHERE type = TextEntity}"> <!-- More Stuff --> </ItemsControl>
(Obviously not valid), but basically I want to "filter" out from the collection only the type that are needed, making it easier to manage in the ViewModel by not having separate collections. (And having to run operations separately on each one because of this)
I'm fairly sure this is not possible, but figured I would ask in case anyone has any ideas, either through XAML or the ViewModel.
Upvotes: 1
Views: 485
Reputation: 17085
As you may already know ItemsControl
automatically selects the correct ItemTemplate
according to the type of each item.
Define an empty DataTemplate for each type derived from MapEntity like below, so that any ItemsControl
(without its ItemTemplate explicitly set), choose from these resources.
<Window.Resources>
<DataTemplate DataType="{x:Type vm:TextEntity}">
</DataTemplate>
<DataTemplate DataType="{x:Type vm:LineEntity}">
</DataTemplate>
</Window.Resources>
Now you need to override one of those for each ItemsControl.
<ItemsControl ItemsSource="{Binding Entities}">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type vm:TextEntity}">
<!-- Template for text entity -->
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
Upvotes: 2
Reputation: 1141
You could have a look at the CollectionViewSource class, and use it's filtering capabilities to filter on type.
The nice thing is that it propagates collection changed events from your underlying ObservableCollection.
Upvotes: 2