具有可观察集合的 WPF 隐式数据模板

本文关键字:数据 WPF 观察 集合 | 更新日期: 2023-09-27 18:31:25

我是WPF的新手,使用MVVM。我有一个视图,我想根据用户在菜单上选择的内容显示不同的内容。其中一件事是另一个具有视图模型 (TempVM) 的用户控件 Temp,所以我正在这样做:

<ContentControl Content="{Binding Path=TempVM}"/>

和 TempVM(类型为 TempViewModel)为空,直到用户单击按钮。它的数据模板是这个

 <DataTemplate DataType="{x:Type vm:TempViewModel}">
        <view:Temp />
    </DataTemplate>

这很好,但我想做的另一件事是在用户单击其他菜单项时显示列表框。所以我正在努力做

<ContentControl Content="{Binding Path=Missions}"/>

(任务是任务数据的可观察集合)并尝试像这样模板化它:

 <DataTemplate DataType="{x:Type ObservableCollection(MissionData)}">
        <StackPanel>
            <ListBox ItemsSource="{Binding}" SelectedItem="{Binding Path=MissionData, Mode=TwoWay}" DisplayMemberPath="MissionName" SelectedValuePath="MissionId" />
            <Button Content="Go"/>
        </StackPanel>
    </DataTemplate>

但是编译器不喜欢类型引用。如果我尝试通过给模板一个键并在 ContentControl 中指定该键来做到这一点,它可以工作,但显然在没有任务时我会看到列表框和按钮。显然,我可以制作一个用户控件和视图模型,并遵循与我对 TempVM 相同的模式,但这似乎太过分了。我走对了路吗,我需要做什么?

具有可观察集合的 WPF 隐式数据模板

据我所知,您尝试将集合用作数据对象,在我看来这是不好的做法。拥有集合的 DataTemplate 也是有问题的,就像你已经看到的那样。我建议您使用ViewModel作为任务集合。

class MissionsSelectionViewModel
{
    public ObservableCollection<Mission> Misssions;
    public MissionData SelectedMission;
    public ICommand MissionSelected;
}

并将数据模板修改为

<DataTemplate DataType="{x:Type MissionsSelectionViewModel}">
    <StackPanel>
        <ListBox ItemsSource="{Binding Missions}" SelectedItem="{Binding Path=MissionData, Mode=TwoWay}" DisplayMemberPath="MissionName" SelectedValuePath="MissionId" />
        <Button Content="Go" Command="{Binding MissionSelected}/>
    </StackPanel>
</DataTemplate>

如果我遵循您的隐式模板模式,我会从ObservableCollection<MissionData>派生一个自定义的非泛型集合MissionDataCollection,并使用它来保留MissionData项。然后我会简单地在 DataType 中引用该集合。此解决方案提供了其他有用的优势,例如对集合的事件聚合。

但是,在我看来,最好的解决方案如下。

  1. IsMissionsListVisible属性添加到 VM。
  2. 将显示列表的ContentControlVisibility 属性绑定到 IsMissionsListVisible 属性。
  3. 使用键控DataTemplate资源。
  4. 实现确定是否IsMissionsListVisible 的逻辑。当所选项目中至少有一个任务时,应该是正确的。但逻辑可能更复杂。

我会这样做。事实上,我通常这样做,它有几个好处。最重要的是,我可以在各种情况下显式控制内容可见性的逻辑(例如异步内容刷新)。