我是WPF新手并使用MVVM。我有一个视图,我想根据用户在菜单上选择的内容显示不同的内容。其中一个是另一个用户控件Temp,它有一个视图模型(TempVM)所以我这样做:
<ContentControl Content="{Binding Path=TempVM}"/>
和TempVM(类型为TempViewModel)在用户单击按钮之前为空。它的数据模板就是这个
<DataTemplate DataType="{x:Type vm:TempViewModel}">
<view:Temp />
</DataTemplate>
没关系,但我要做的另一件事是当用户点击不同的菜单项时显示一个列表框。所以我想做
<ContentControl Content="{Binding Path=Missions}"/>
(Missions是一个可观察的MissionData集合),并试图模仿它:
<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中指定该键它可以工作但显然我看到ListBox和按钮没有任务时。显然,我可以创建一个用户控件和视图模型,并遵循与TempVM相同的模式,但它似乎超越了顶部。我是否正确地对待这一点以及我需要做什么?
答案 0 :(得分:2)
从我看到的是你尝试使用Collection作为数据对象,这在我看来是不好的做法。拥有DataTemplate的集合也存在问题,就像您已经见过的那样。我建议你使用ViewModel作为你的任务集合。
class MissionsSelectionViewModel
{
public ObservableCollection<Mission> Misssions;
public MissionData SelectedMission;
public ICommand MissionSelected;
}
并将您的datatemplate修改为
<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>
答案 1 :(得分:1)
如果我要遵循隐式模板的模式,我会从MissionDataCollection
派生自定义非泛型集合ObservableCollection<MissionData>
并使用它来保留MissionData
个项目。然后我会在DataType
中引用该集合。此解决方案提供了其他优点,例如集合上有用的事件聚合。
然而,在我看来,最好的解决方案如下。
IsMissionsListVisible
属性。Visibility
的{{1}}属性绑定到ContentControl
属性。IsMissionsListVisible
资源。DataTemplate
的逻辑。据推测,当所选项目中至少有一个任务时,它应该是真的。但逻辑可能更复杂。我会这样做。事实上,我通常这样做,它有几个好处。最重要的是,我可以在各种情况下明确控制内容可见性的逻辑(例如,异步内容刷新)。