【问题标题】:MVVM, Confused about ViewModelLocator and DataTemplate, leading to ViewFirst vs ViewModel firstMVVM,对 ViewModelLocator 和 DataTemplate 感到困惑,导致 ViewFirst vs ViewModel first
【发布时间】:2015-02-21 21:07:11
【问题描述】:

我使用 MVVMLight,它带有一个 ViewModelLocator。

我最初的项目提出了以下问题。我有一个在启动应用程序时呈现的 MainView。根据单击的按钮,它通过我的 MainView 中的 ContentControl 呈现 View1 或 View2(每个都是用户控件)。

我在 MainViewModel 中找到了正确的视图模型。但我发现我还需要一个 DataTemplate 以便 View1 和 View2 中的用户控件将在 MainView 中正确呈现,否则它只会显示基于文本的类名称。

我对以下内容感到困惑:

a) 我需要视图模型定位器和 DataTemplate 来完成上述任务吗?我刚刚进入 WPF,但我认为我读到其中一个是必需的,而不是两者都需要。或者更具体一点:为什么我的视图中有DataContext="{Binding LiveDataViewModel, Source={StaticResource Locator}}">(它将绑定到它自己的视图模型)但仍然需要一个DataTemplate?

b) 这是视图模型优先方法还是视图优先方法?

c) 我尝试了一个代码背后的解决方案,实际上我花了 4 行代码来完成完全相同的事情,这让我花了很多类、绕道、eventToCommand 和转换器 [因为触发视图选择的控件只会引发事件不是命令],数据模板,视图模型定位器,不同的视图模型......这看起来像是付出了巨大的代价却没有任何优势。把它放到后面的代码中在我看来非常好,因为它是纯 UI 内容(选择视图并绑定到内容控件,完成)。我在这里错过了什么吗?我会通过背后的代码放弃什么?

我是 WPF 和 MVVM 的新手,现在我非常沮丧,因为感觉就像我在一个看似微不足道的问题上绕圈子。

【问题讨论】:

  • a MainView that is rendered upon stating up the app. Depending on buttons clicked it renders either View1 or View2 (each are user controls) via ContentControl inside my MainView. - 这听起来像TabControl 对我来说。不要试图重新发明轮子,它已经被发明了;)
  • @HighCore,它是 DevExpress 中的 RibbonControl,我需要根据功能区页面选择更改视图(注意:不是功能区组中的按钮)。所以请放心,这里没有什么是重新发明的,;-) [我使用了术语按钮,因为我的问题不是我如何实现 EventToCommanding]。
  • 不完全是您问题的答案,但是您是否查看过 Frame 控件?在您的功能区控件引发的事件中,您可以向 MainView 发送一条消息以更改框架的 Source 属性。
  • 顺便说一句,SelectedPageName 问题已在 13.1.20 和 13.2.8 apparently 中修复。您应该报告它仍在当前版本中发生(如果确实如此)

标签: c# wpf mvvm mvvm-light


【解决方案1】:

如果这个答案听起来很基础,我很抱歉,但听起来你可能仍在学习 WPF 并误解了一些关键问题。

首先,WPF 应用程序有两层:

  • 由您在屏幕上看到的对象组成的 UI 层
  • 以及位于 UI 后面的数据层,称为 DataContext

当您进行绑定时,您是从数据层提取数据并将其放置在 UI 层中。

ViewModelLocator 影响数据层。它用于找到合适的数据对象以放置在 UI 对象后面。

现在,在数据对象直接插入 UI 层的情况下,例如任何具有直接绑定到其数据层的 .Content.ItemsSource 属性的东西,WPF 呈现数据对象的默认方式是使用一个TextBlock,显示对象的.ToString()

您可以覆盖它并告诉 WPF 如何使用 DataTemplate 绘制任何类型的对象。您可以告诉控件使用特定模板呈现,也可以告诉 WPF 使用特定 DataTemplate 自动呈现类型 X 的 UI 层中的任何对象。

所以回答你的问题

a) 我需要视图模型定位器和 DataTemplate 来完成上述任务吗?或者更具体一点:为什么我的视图中有DataContext="{Binding LiveDataViewModel, Source={StaticResource Locator}}">,但仍需要一个DataTemplate?

这是两个独立的项目。 ViewModelLocator 定位 UI 对象后面的数据项,DataTemplate 告诉 WPF 如何绘制该项目。

您的绑定是说“将数据层 (DataContext) 绑定到 Locator.LiveDataViewModel”,我最好的猜测是您的 XAML 中的某些内容将 ItemsSourceContent 直接绑定到数据层,使用 XAML 之类的Content="{Binding }"

b) 这是视图模型优先方法还是视图优先方法?

我认为,无论何时您使用 ViewModelLocator,它都是一种视图优先的方法,因为 View 负责从 Locator 获取它的数据项。在 View 调用它之前,数据不存在。

就我个人而言,我从不使用ViewModelLocator,因为我不喜欢它的限制,并且更喜欢模型优先的方法,但这并不意味着你不能使用它。

c) 我尝试了一个代码背后的解决方案,实际上我花了 4 行代码来完成完全相同的事情,这让我花了很多类、绕道、eventToCommand 和转换器 [因为触发视图选择的控件只会引发事件不是命令],数据模板,视图模型定位器,不同的视图模型......这看起来像是付出了巨大的代价却没有任何优势。把它放到后面的代码中在我看来非常好,因为它是纯 UI 内容(选择视图并绑定到内容控件,完成)。我在这里错过了什么吗?我会通过背后的代码放弃什么?

我不知道你的代码是什么样的,但是听起来里面有很多不必要的代码。 MVVM 模式背后的想法是让所有应用程序逻辑都驻留在类中,而所有用户界面逻辑都驻留在 UI 控件中。 WPF 非常适合这种设计,因为它的绑定系统。

这使得将备用用户界面连接到您的应用程序变得很容易,最常见的是测试脚本。它还具有使 UI 与业务逻辑完全分离的优势,这在与专门的 UI 团队合作时非常有帮助。

我个人对每个 WPF 应用程序都使用 MVVM,即使是非常简单的应用程序。我可能会在简单的应用程序中稍微模糊一些规则,但是当存在 MVVM 选项时,我永远无法回到旧的 WinForms 构建应用程序的风格。

如果您有兴趣,我已经为 WPF 初学者写了几篇博客文章,如果您刚开始,您可能会觉得这些文章很有用:

希望这会有所帮助,祝你好运:)

【讨论】:

  • 非常感谢这个演练,是的,我是一个该死的 WPF 初学者。很明显,我看到了 MVVM 的优势。我没有发现我的最后一个问题得到很好的解决,因为是否使用代码或 xaml 似乎不会影响一个人是否遵守 MVVM 模式。因此,我看到了可测试性问题以及更好地在 UI 团队和业务逻辑开发人员之间分离工作的能力,但我不认为代码隐藏消除了这些优势。我特意问为什么....
  • ...有些人似乎反对在 UI 对象的代码隐藏部分中实现大部分 UI 逻辑的想法。乍一看,我发现在某些问题上使用代码隐藏有很多优势,例如当第三方控件不提供经过深思熟虑的命令绑定并且主要依赖于事件时:它需要在代码中使用一行代码来处理事件而 xaml 中的事件触发器、转换器、事件到命令等似乎使生活变得不必要地复杂。
  • @MattWolf 如果你有 UI 特定的逻辑,它应该放在代码隐藏文件中。我一直这样做。但如果它是业务逻辑,那么它应该放在 ViewModel 中,它不应该是 View 层的一部分。在大多数情况下,我使用AttachedCommandBehavior,我希望 ViewModel 通过一些业务逻辑处理来响应 UI 事件,但有时我会变得懒惰,也只是使用 UI 事件来调用 ViewModel 命令。重点是保持图层分开,而不是警察编码风格。
  • 这很有道理,感谢您花时间解释和分享您的宝贵见解。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-20
  • 1970-01-01
  • 2021-11-28
  • 1970-01-01
  • 1970-01-01
  • 2012-12-19
  • 2021-06-27
相关资源
最近更新 更多