【问题标题】:DataBind to ObservableCollection, displaying only elements of a certain derived classDataBind 到 ObservableCollection,只显示某个派生类的元素
【发布时间】:2015-04-07 17:56:12
【问题描述】:

我正在使用 MVVM 模式在 WPF 中开发一个应用程序,并且遇到了一些可能有点独特的东西。

我有一个抽象类MapEntity,它代表一个可以显示在我的应用程序绘图表面上的实体。其他类如LineEntityTextEntity等,继承自MapEntity

为了显示这些,我为每种类型创建了一个ObservableCollection,并将其绑定到我的 XAML,它获取每个实体的属性并显示它们。 (例如,使用TextEntity 的颜色和文本创建一个文本框)

同时管理这些实体感觉有点像 hack。如果每个实体都有一堆集合,我可以创建一个ObservableCollection<MapEntity>,并将所有实体添加到其中。这将使处理它们更容易,例如当用户拖动实体时检查它们的边界,或者通过MapEntity 中定义的更新方法更新它们。标准继承的东西。

使用这种技术时出现问题,有没有办法创建一个绑定到单个集合的ItemsControl(而不是将每个ItemsControl 绑定到TextEntityLineEntity 等的集合),但只显示某种类型的元素?

例如:

视图模型:

public ObvervableCollection<MapEntity> Entities { get; set; //OnPropertyChanged stuff}
...
Entities.Add(new LineEntity(...));
Entities.Add(new TextEntity(...));

因此,我将不同的MapEntities 添加到单个集合中,而不是为每种类型添加多个。

查看:

使用单独的集合,我可以将每个 ItemsControl 项目绑定到特定集合,但是使用一个 Entities 集合,我找不到“过滤”从 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>

(显然无效),但基本上我想从集合中“过滤”出只需要的类型,从而通过没有单独的集合来更容易地在 ViewModel 中进行管理。 (因此必须对每个单独运行操作)

我很确定这是不可能的,但我想如果有人有任何想法,我会通过 XAML 或 ViewModel 询问。

【问题讨论】:

    标签: c# wpf xaml mvvm observablecollection


    【解决方案1】:

    您可能已经知道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>
    

    【讨论】:

    • 谢谢,这太完美了!如果类型不是DataType,您是否知道它是否正在为 ItemControls 创建一个“空白”元素,或者 WPF 是否会看到只定义了一个 DataTemplate 而不会费心“尝试”将其添加到控件中?
    • 其实我不确定,但我认为 ItemsControl 在找不到合适的模板时会显示一个虚拟文本(完整的命名空间和数据类型的类名)。
    【解决方案2】:

    您可以查看CollectionViewSource 类,并使用它的过滤功能来过滤类型。

    好消息是它从底层的 ObservableCollection 传播集合更改事件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-01
      • 2017-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-15
      相关资源
      最近更新 更多