具有可观察集合的 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 相同的模式,但这似乎太过分了。我走对了路吗,我需要做什么?
据我所知,您尝试将集合用作数据对象,在我看来这是不好的做法。拥有集合的 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
中引用该集合。此解决方案提供了其他有用的优势,例如对集合的事件聚合。
但是,在我看来,最好的解决方案如下。
- 将
IsMissionsListVisible
属性添加到 VM。 - 将显示列表的
ContentControl
的Visibility
属性绑定到IsMissionsListVisible
属性。 - 使用键控
DataTemplate
资源。 - 实现确定是否
IsMissionsListVisible
的逻辑。当所选项目中至少有一个任务时,应该是正确的。但逻辑可能更复杂。
我会这样做。事实上,我通常这样做,它有几个好处。最重要的是,我可以在各种情况下显式控制内容可见性的逻辑(例如异步内容刷新)。