【问题标题】:WPF: MVVM says no to converters but I need nice enum valuesWPF:MVVM 对转换器说不,但我需要好的枚举值
【发布时间】:2011-04-18 23:06:49
【问题描述】:

在模型层,我定义了一个枚举:

public enum MemberStatus
{
    ActiveMember = 0,
    InactiveMember = 1, 
    Associate = 2,
    BoardMember = 3,
    Alumni = 4
}

在我看来,我有一个组合框,其中填充了这些枚举值:

<UserControl.Resources>

  <ObjectDataProvider 
      x:Key="memberStatusesDataProvider" 
      ObjectType="{x:Type system:Enum}" 
      MethodName="GetValues">
    <ObjectDataProvider.MethodParameters>
      <x:Type TypeName="model:MemberStatus" />
    </ObjectDataProvider.MethodParameters>
  </ObjectDataProvider>

</UserControl.Resources>
...
<ComboBox 
    ItemsSource="{Binding Source={StaticResource memberStatusesDataProvider}}" 
    SelectedItem="{Binding Path=Status}" />
...

这会导致组合框的选项与枚举中定义的值完全相同。虽然这是我最初的目标,但我希望为用户提供更好的演示,如下所示:

  • 组合框选项:
    • 活跃成员
    • 非活动成员
    • 关联
    • 董事会成员
    • 校友

另外,如果应用程序中的语言发生变化,我需要该语言的枚举值。为了解决这个问题,我首先想到的是为MemberStatus 枚举值创建一个转换器。我发现这篇关于该主题的漂亮文章:http://www.codeproject.com/KB/WPF/FriendlyEnums.aspx 但是 MVVM 模式说几乎根本不需要创建它们——我同意这一点。然而,在这个例子中,这种肯定对我不利。

应该怎么做?谢谢。

【问题讨论】:

  • 您从哪里了解到 MVVM 不需要转换器?
  • 我会考虑改变设计而不是调整转换器。一个好的解决方案是创建两个类 - MemberStatusAvailableMemberStatusAvailableMemberStatus 将扩展 List&lt;MemberStatus&gt; 并在构造函数中初始化自身。可能作为单例实现。
  • @nlawalker:我在 Josh Smith 的博客和其他几个来源中找到了它。它实际上在 MVVM 讨论中经常被提及。就个人而言,我同意这种说法,因为视图模型的目的是将模型转换为视图——它可能会为视图做好准备。
  • 我不同意关于不在 MVVM 中使用转换器的说法。 WPF 广泛使用内置转换器,我经常在我的 MVVM 编程中使用它们。我和他们没有任何问题。我对诸如“但是 MVVM 模式说不应该创建它们”之类的笼统陈述持保留态度。这只是一个人的观点,许多人不同意。

标签: wpf xaml mvvm


【解决方案1】:

关于 MVVM 使价值转换器过时的观点似乎来自 Josh Smith,他在他的博客文章 The Philosophies of MVVM 中说:

... ViewModel 类本质上是一个 类固醇上的值转换器,因此 渲染 IValueConverter 与大多数人无关的界面 绑定。

我从中得到的(我同意他的价值)是视图模型负责从模型的世界视图到视图的所有转换,从而使转换器过时。

在模型中暴露给 UI 的枚举(这是一种非常以数据为中心的数据类型)绝对是一种味道 - 如果只是出于您看到的原因,向用户显示不太理想的信息。

在您的视图模型中放置一个从枚举到 UI 字符串的映射。

【讨论】:

  • 虽然 - 如果代码更简单、更易读,那么就使用值转换器方法!但在大多数情况下,“类固醇转换器”仍然存在。
  • 关键是“大多数”绑定。可能有一两种情况,最好有一个转换器。
  • @David:感谢您的回答。在我的情况下,我遇到了映射问题,在stackoverflow.com/questions/5706500/… 进行了解释。所以,基本上,如果我依赖数据模板并使用模型类作为它们的数据类型,我不能使用视图模型中定义的映射属性,因为那不是模板的数据上下文。如果我应该使用视图模型属性,那么为链接问题提供的解决方案没有意义。我在这里有两种想法:)请指教,谢谢。
  • @Boris 我看了那个问题并同意评论者提到的单个 VM 有多个数据模板。我已经有一段时间没有认真地在 WPF 中工作了,但请记住这样做。我能说的是,如果你(我认为)直接绑定到你的模型,那么这会破坏 MVVM 的好处。此外,理想情况下,每个视图应该有 1 个 VM,用于处理各种模型元素的所有转换。我偶尔会有一个虚拟机在视图中为用户控件提供服务,但那是当用户控件本质上是一个独立的组件时。抱歉,我现在无法提供具体代码
  • @David 这正是我的想法!直接绑定到模型没有任何意义,MVVM 明智。此外,我同意每个视图拥有 1 个视图模型的概念,但也同意每个独立组件拥有 1 个视图模型的概念。所以,为了结束这一点,最后一个问题:对于在模型中拥有大量属性并将它们中的每一个映射到视图模型中以避免直接绑定的想法,您感觉如何?我之所以这么问是因为在许多情况下,事实证明映射是直接的,1 对 1,这使得它看起来是多余的(并且该模式的目的是减少冗余)。
【解决方案2】:

转换器不仅仅用于转换enums。转换器也比一次性的viewmodel可重用

  • 我可能想将bool 转换为Brush,我可以在视图中指定所有参数。

  • 或者我想通过数据绑定将string 转换为DateTime 并再次返回。也许我想将所有内容都转换为大写。然后是我最喜欢的 BoolToVisibilityConverter

我不想在我的VMs 中放置明确的直接间接 代码,只是为了让一些少数群体满意。我认为他们忘记的一点是转换器很容易从 Expression Blend 中访问

转换器是 WPF 的重要组成部分,并补充了 viewviewmodel 之间的绑定。

我认为你没有理由不能将它们用于enums。

【讨论】:

    【解决方案3】:

    MVVM 并没有真正确定 WPF 的哪些部分是允许的和不允许的。如果转换器可以轻松实现您的目标,则可以使用它们。我什至建议更进一步,制作一个MarkupExtension 来提供枚举值及其字符串等价物。您可以将字符串存储在每个枚举值的 DescriptionAttribute 中。

    【讨论】:

    • 所以从你的角度来看,它最终是转换器,对吧?如果我理解正确,我会在那里对字符串映射进行枚举值。另外,还有一件事,我认为DescriptionAttribute 不是一个好主意,因为这样值是硬编码的。如果我在应用程序中支持不同的语言,那么DescriptionAttribute 将不得不动态更改。感谢您提供答案,干杯。
    • 您可以提供可识别语言的源集合。我在我们的产品中使用的标记扩展支持从资源文件中读取以检索描述。
    • @user7116 这太可怕了,太懒惰了。避免避免避免。 resx 文件已经实现了这一点。现有的本地化工具不会替换属性中的字符串数组。
    【解决方案4】:

    我不同意 MVVM 确实使 ValueConverters 过时。在很多场景中,实现 ValueConverter 比在 ViewModel 类中实现转换更有意义。

    您可能对WPF Application Framework (WAF)BookLibrary 示例应用程序感兴趣。它展示了如何在 MVVM 应用程序中本地化枚举。请查看 BookLibrary.Presentation / Converters / LanguageToStringConverter 类。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-07-07
      • 2015-08-04
      • 2017-01-18
      • 2020-01-12
      • 2012-01-30
      • 1970-01-01
      • 2015-09-11
      相关资源
      最近更新 更多