DataBind到ObservableCollection,只显示某个派生的元素class
DataBind to ObservableCollection, displaying only elements of a certain derived class
我正在使用 MVVM 模式在 WPF 中开发应用程序并且遇到了一些可能有点独特的东西。
我有一个抽象 class MapEntity
,它表示可以在我的应用程序的绘图表面上显示的实体。其他class如LineEntity
、TextEntity
等继承自MapEntity
.
为了显示这些,我为每种类型创建了一个 ObservableCollection
并将其绑定到我的 XAML,它获取每个实体的属性并显示它们。 (例如,创建一个颜色和文本为 TextEntity
的文本框)
一起管理这些实体感觉有点像黑客。如果每个实体都有一堆集合,我可以创建一个 ObservableCollection<MapEntity>
,然后将所有实体添加到其中。这将使处理它们更容易,例如在用户拖动实体时检查它们的边界,或通过 MapEntity
中定义的更新方法更新它们。标准继承的东西。
问题是在使用这种技术时出现的,有没有办法创建一个绑定到这个单一集合的 ItemsControl
(而不是让每个 ItemsControl
绑定到 TextEntity
, LineEntity
, etc), 却只显示某种类型的元素?
例如:
ViewModel:
public ObvervableCollection<MapEntity> Entities { get; set; //OnPropertyChanged stuff}
...
Entities.Add(new LineEntity(...));
Entities.Add(new TextEntity(...));
因此,我将不同的 MapEntities
添加到单个集合中,而不是为每种类型添加多个。
查看:
使用单独的集合,我可以将每个 ItemsControl
项目绑定到一个特定的集合,但是使用一个 Entities
集合,我无法找到 "filter" 个元素的方法某些类型派生自 MapEntity
.
所以不要这样做:
<ItemsControl ItemsSource="{Binding LineEntities}"> <!-- More Stuff --> </ItemsControl>
<ItemsControl ItemsSource="{Binding TextEntities}"> <!-- More Stuff --> </ItemsControl>
我想做:
<ItemsControl ItemsSource="{Binding Entities WHERE type = LineEntity}"> <!-- More Stuff --> </ItemsControl>
<ItemsControl ItemsSource="{Binding Entities WHERE type = TextEntity}"> <!-- More Stuff --> </ItemsControl>
(显然无效),但基本上我想 "filter" 只从集合中取出所需的类型,从而通过没有单独的集合更容易在 ViewModel 中进行管理。 (因此必须 运行 分别对每一个进行操作)
我相当确定这是不可能的,但我想如果有人有任何想法,我会通过 XAML 或 ViewModel 询问。
您可以查看 CollectionViewSource class,并使用它的过滤功能来过滤类型。
好处是它从您的底层 ObservableCollection 传播集合更改事件。
您可能已经知道 ItemsControl
会根据每个项目的类型自动选择正确的 ItemTemplate
。
为从 MapEntity 派生的每个类型定义一个空的 DataTemplate,如下所示,以便任何 ItemsControl
(没有明确设置其 ItemTemplate),从这些资源中选择。
<Window.Resources>
<DataTemplate DataType="{x:Type vm:TextEntity}">
</DataTemplate>
<DataTemplate DataType="{x:Type vm:LineEntity}">
</DataTemplate>
</Window.Resources>
现在您需要为每个 ItemsControl 覆盖其中一个。
<ItemsControl ItemsSource="{Binding Entities}">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type vm:TextEntity}">
<!-- Template for text entity -->
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
我正在使用 MVVM 模式在 WPF 中开发应用程序并且遇到了一些可能有点独特的东西。
我有一个抽象 class MapEntity
,它表示可以在我的应用程序的绘图表面上显示的实体。其他class如LineEntity
、TextEntity
等继承自MapEntity
.
为了显示这些,我为每种类型创建了一个 ObservableCollection
并将其绑定到我的 XAML,它获取每个实体的属性并显示它们。 (例如,创建一个颜色和文本为 TextEntity
的文本框)
一起管理这些实体感觉有点像黑客。如果每个实体都有一堆集合,我可以创建一个 ObservableCollection<MapEntity>
,然后将所有实体添加到其中。这将使处理它们更容易,例如在用户拖动实体时检查它们的边界,或通过 MapEntity
中定义的更新方法更新它们。标准继承的东西。
问题是在使用这种技术时出现的,有没有办法创建一个绑定到这个单一集合的 ItemsControl
(而不是让每个 ItemsControl
绑定到 TextEntity
, LineEntity
, etc), 却只显示某种类型的元素?
例如:
ViewModel:
public ObvervableCollection<MapEntity> Entities { get; set; //OnPropertyChanged stuff}
...
Entities.Add(new LineEntity(...));
Entities.Add(new TextEntity(...));
因此,我将不同的 MapEntities
添加到单个集合中,而不是为每种类型添加多个。
查看:
使用单独的集合,我可以将每个 ItemsControl
项目绑定到一个特定的集合,但是使用一个 Entities
集合,我无法找到 "filter" 个元素的方法某些类型派生自 MapEntity
.
所以不要这样做:
<ItemsControl ItemsSource="{Binding LineEntities}"> <!-- More Stuff --> </ItemsControl>
<ItemsControl ItemsSource="{Binding TextEntities}"> <!-- More Stuff --> </ItemsControl>
我想做:
<ItemsControl ItemsSource="{Binding Entities WHERE type = LineEntity}"> <!-- More Stuff --> </ItemsControl>
<ItemsControl ItemsSource="{Binding Entities WHERE type = TextEntity}"> <!-- More Stuff --> </ItemsControl>
(显然无效),但基本上我想 "filter" 只从集合中取出所需的类型,从而通过没有单独的集合更容易在 ViewModel 中进行管理。 (因此必须 运行 分别对每一个进行操作)
我相当确定这是不可能的,但我想如果有人有任何想法,我会通过 XAML 或 ViewModel 询问。
您可以查看 CollectionViewSource class,并使用它的过滤功能来过滤类型。
好处是它从您的底层 ObservableCollection 传播集合更改事件。
您可能已经知道 ItemsControl
会根据每个项目的类型自动选择正确的 ItemTemplate
。
为从 MapEntity 派生的每个类型定义一个空的 DataTemplate,如下所示,以便任何 ItemsControl
(没有明确设置其 ItemTemplate),从这些资源中选择。
<Window.Resources>
<DataTemplate DataType="{x:Type vm:TextEntity}">
</DataTemplate>
<DataTemplate DataType="{x:Type vm:LineEntity}">
</DataTemplate>
</Window.Resources>
现在您需要为每个 ItemsControl 覆盖其中一个。
<ItemsControl ItemsSource="{Binding Entities}">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type vm:TextEntity}">
<!-- Template for text entity -->
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>