【问题标题】:Show MessageBox in Winforms with MVVM pattern使用 MVVM 模式在 Winforms 中显示 MessageBox
【发布时间】:2016-01-24 17:54:17
【问题描述】:

如何根据ViewModel方法的结果调用MessageBox.Show()

视图模型

Public Class PersonViewModel
    Inherits ViewModels.ViewModelBase 'basic INotifyPropertyChanged staff

    Private _Model As Person
    Public Property FirstName As String
    Public Property LastName As String

    'BasicSub is class implemented ICommand taking Execute method as parameter
    Public Property SaveCommand As New Commands.BasicSub(AddressOf Me.SaveModel)

    Private Sub SaveModel()
        If _Model.Save() = False Then
            'Here inform View about saving wasn't successful
        End If
    End Sub
End Class

查看

Public Class PersonView 
    Inherits Form

    'I use BindingSource for bindings
    Private BindingSourceViewModel As BindingSource

    Public Sub New(viewmodel As Object)
        Me.InitializeComponents()

        Me.BindingSourceViewModel.DataSource = viewmodel
    End Public

End Class

View 有一个按钮,其 Click 事件绑定到 Command 属性

我将 MVVM 理解为简单的关注点分离。
View(在 Winforms 中是 Form)只有自己的逻辑。设计器代码或代码隐藏无关紧要。
ViewModel 了解模型但不了解视图。

现在我对如何根据Save 命令/方法的结果调用MessageBox 并同时保持ViewViewModel 分隔的问题很少出价?
因为 MessageBox.Show 显然是 View 的一部分

目前,我使用的解决方法在我看来打破了MVVM 模式。
MessageBox.Show 如果_Model.Save 返回 false,则从 SaveModel() 方法中的 ViewModel 执行。

我已经检查了答案WPF MessageBox with MVVM pattern?,但此时不受使用某些中间类型的影响。我试图将 Views 和 ViewModels 保留在不同的项目中,并且 Views 除了资源之外没有对其他应用程序库的任何引用

@HighCore,我知道WinformsWPF 之间的区别:)

【问题讨论】:

  • 我不知道这是否是最好的方法,但我通过从 ViewModel 发送消息并在 View 中注册一个处理程序来处理这个问题。通常,您需要做的不仅仅是显示 MessageBox,因此注册处理程序以侦听从 ViewModel 发送的错误消息非常方便,恕我直言……但我并不声称自己是 MVVM 专家。
  • 正如 Filburt 所说,你应该使用 messenger 模式,我写了一篇文章解释了这种模式和其他 mvvm 主题:blog.rsuter.com/…
  • 以防万一您还没有使用它:MVVM FX / Caliburn.Micro 似乎为 Windows 窗体提供了一个不错的 mvvm 框架。
  • @Filburt,eventhandler 方法,如果我理解正确,意味着 View 需要知道 ViewModel 类型才能订阅事件。在我的例子中,View 将 ViewModel 作为构造函数中 Object 类型的参数。
  • @Fabio 不,视图只需要了解消息类型,如果需要,还需要了解消息中包含的(模型)类型。消息类型可以/应该位于专用项目中,并像您的模型类型一样被引用。而且,严格来说,您声明的 Message Handlers 与用于按钮单击事件等的 Commands 不同。

标签: .net winforms mvvm


【解决方案1】:

作为视觉元素,任何消息框实际上都是视图的一部分。因此,如果您直接从ViewModel 显示您的消息框(定义一个调用MessageBox.Show() 方法的命令),这个简单的代码将打破主要的MVVM 概念——ViewModels 不能引用Views——并且使它无法编写ViewModel 的单元测试。为了解决这个难题,您可以使用服务 概念。服务是一种 IOC 概念,它删除 ViewModel 和 View 层之间的任何引用。在代码中,服务是在 ViewModel 代码中使用的接口,无需假设“何时”和“如何”实现此接口:

Public Class PersonViewModel
    Protected ReadOnly Property MessageBoxService() As IMessageBoxService
        Get 
            Return Me.GetService(Of IMessageBoxService)()
        End Get 
    End Property
    Public Sub Save()
        If Not _Model.Save() Then
            MessageBoxService.Show("Something wrong!")            
        End If
    End Sub 
End Class

您可以使用 DI/IoC 为您提供带有 IMessageBoxService 实现的 View Model。

附:如果您使用 DevExpress WinForms 控件,您可以使用 POCO-ViewModels, bindings&commanding, services, messenger and etc. 等很酷的东西扩展您的 MVVM 应用程序 - 所有这些都完全适用于 WinForms 环境。

【讨论】:

  • service 概念是否意味着我需要为每种类型的 View 实现 IMessageBoxService 接口?例如用于 WPF、Winforms 和测试
  • @Fabio 没错。您还可以根据您的应用程序 UI 类型提供具体服务的不同实现(例如,您可以使用标准的、外皮的弹出消息框)。然后只需在您的 DI/IoC 容器中注册此服务的具体实现,即可在整个应用程序中更改消息传递 UI。无需对 ViewModels/Views 代码进行任何更改。
  • View 和 ViewModel 在我的案例中位于不同的项目中,所以我确实将 Interface 放在 ViewModel 项目中,并且接口的实现在 View 或 Test 项目中,谢谢
猜你喜欢
  • 2012-12-27
  • 2013-03-03
  • 2011-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-28
  • 2020-05-21
相关资源
最近更新 更多