【问题标题】:WPF implicit datatemplate with observablecollection带有 observablecollection 的 WPF 隐式数据模板
【发布时间】:2012-04-18 08:37:27
【问题描述】:

我是 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}"/>

(任务是 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 所做的相同模式,但它似乎过分了。我在这件事上走的是正确的道路吗?我需要做什么?

【问题讨论】:

标签: c# wpf


【解决方案1】:

据我所知,您尝试将 Collection 用作数据对象,我认为这是不好的做法。拥有一个集合的 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>

【讨论】:

  • 我最后是这样弄的。 But when the mission is selected I need to go back to the original view model - that TempVM I have is for displaying a new empty mission or a selected mission.那么我是否需要将父视图模型传递给 MissionsSelection 视图模型,以便在其中设置父视图模型?
  • 你可以这样做,这真的取决于你的应用程序设计。你也可以让父 vm 从 MissionsSelectionViewModel 中读取属性,该属性适当地存储在其中。
【解决方案2】:

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

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

  1. IsMissionsListVisible 属性添加到您的虚拟机。
  2. 将显示列表的ContentControlVisibility 属性绑定到IsMissionsListVisible 属性。
  3. 使用带密钥的DataTemplate 资源。
  4. 实现确定是否IsMissionsListVisible 的逻辑。假设在所选项目中至少有一个任务时应该为真。但逻辑可能更复杂。

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

【讨论】:

  • 大声笑我刚从重构你所描述的内容到使用 DataTemplates,因为我虽然这更聪明......但我遇到了与 Nix 描述的相同的问题。所以我现在也将留在 Visibility 属性上....:D
猜你喜欢
  • 2018-10-14
  • 1970-01-01
  • 1970-01-01
  • 2011-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多