MVVM违规

22 浏览
0 Comments

MVVM违规

我想解决关于MVVM违规的一些问题。为了演示这些情况,我创建了一个包含一些项目的解决方案。

以下是解决方案的定义(项目):

  1. View(它是一个WPF类库,显然它包含了视图)
  2. ViewModel(它是一个类库,显然它包含了视图模型)
  3. Model(它是一个类库,显然它包含了模型)
  4. Domain(它是一个类库,包含了应用程序数据模型)
  5. Core(它是一个类库,包含了WPF的核心功能,如RelayCommand或EventToCommand)
  6. Application(它是一个WPF应用程序,也是启动项目)
  7. ExternalCustomControl(它是一个由虚构的第三方公司创建的WPF自定义控件库)

我建议你下载整个解决方案以更好地理解,下载链接在这里:这里

第一个问题:

在MainWindow.xaml中,我有一个用于窗口的Closing事件的EventToCommand,并将其附加到MainWindowClosingCommand,其中PassEventArgsToCommand设置为True。然后,在MainViewModel中,有一个名为OnMainWindowClosing的命令处理程序:

private void OnMainWindowClosing(object parameter)
{
  var arg = parameter as CancelEventArgs;
  // 如何向用户显示消息对话框?
  // 我需要将消息发送给视图来显示MessageBox对话框,然后窗口再将答案返回给我继续执行吗?
  // IMessageBoxService违反了MVVM吗?
  // 以下代码是否违反了MVVM?
  // 取消窗口关闭不是UI层的职责吗?
  arg.Cancel = true;
}

每当你想设置e.Handled或e.Cancel时,你都会遇到这个问题。你知道是否有其他不需要将参数强制转换为CancelEventArgs的方法吗?

第二个问题:

在MainWindow.xaml中,我有一个用于Grid的PreviewMouseDown事件的EventToCommand,并将其附加到MouseClickCommand,其中PassEventArgsToCommand设置为True。然后,在MainViewModel中,有一个名为OnMouseClick的命令处理程序:

private void OnMouseClick(object parameter)
{
  // var arg = parameter as MouseButtonEventArgs; 
  // 这是违反MVVM的:强制转换参数为MouseButtonEventArgs需要在ViewModel项目中添加对PresentationCore.dll的引用
  // 更糟糕的是,在大多数情况下,我们需要知道事件的原始来源(可能是StackPanel或Label等),这再次违反了MVVM
  // 所以有什么解决方法吗?
}

第三个问题:

我在MainWindow中使用了第三方控件(比如Infragistics或DevExpress或任何其他第三方控件,这里只是在我的解决方案中创建了一个虚构的控件ExternalCustomControl)。示例代码如下:

ThirdPartyCustomControl有一个类型为IEnumarabe的属性(CustomControlDataModel是ExternalCustomControl程序集中存在的类型)。但是你知道,如果你想在MainViewModel中为该控件创建一个类型为CustomControlDataModel的属性,你必须在ViewModel项目中添加对ExternalCustomControl.dll的引用,这违反了MVVM。所以我创建了一个名为MyDataModel的类型,并将控件的ItemsSource绑定到MainViewModel中的MyItemsSource属性:

// 如果我将MyItemsSource定义为List,我必须添加对ExternalCustomControl.dll的引用
// 并且我认为这再次违反了MVVM(因为ExternalCustomControl.dll是UI侧的控件程序集)
public List MyItemsSource { get; set; }

所以我将类型为CustomControlDataModel的属性绑定到类型为MyDataModel的属性,当然我需要一个转换器:

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
  // 假设源数据(MyDataModel)很大(例如100万个),这个(虚拟的)转换会影响性能
  if (value is List)
  {
    var result = new List();
    (value as List).ForEach(myVal =>
      {
        var custDataModel = new CustomControlDataModel();
        custDataModel.ID = myVal.ID;
        custDataModel.Name = myVal.Name;
        custDataModel.Age = myVal.Age;
        result.Add(custDataModel);
      });
    return result;
  }
  return value;
}

问题是,你是否知道有比这个虚拟转换更好的方法,或者你通常会将第三方程序集同时添加到视图和视图模型中吗?

这些是我面临的问题,如果你知道其他问题,请分享你的经验。

0
0 Comments

MVVM Violations(MVVM违规)

在上述内容中,出现了一些违反MVVM模式的问题。以下是这些问题的原因和解决方法。

问题1:在XAML中使用了命令绑定的方式来处理窗口关闭事件。

原因:在MVVM模式中,应该避免在XAML中直接处理事件,而是通过绑定命令来处理用户交互。

解决方法:在ViewModel中添加一个ClosingCommand属性,并通过命令绑定将窗口关闭事件与该属性关联起来。

问题2:在ViewModel中使用了MessageBox.Show来显示消息框。

原因:在MVVM模式中,ViewModel应该与视图解耦,不应该直接调用视图相关的功能,如显示消息框。

解决方法:可以通过使用依赖注入或事件聚合器等方式,将消息框显示的功能移到其他层中。

问题3:在XAML中直接使用了第三方控件的特定属性和事件。

原因:在MVVM模式中,应该尽量避免直接使用视图的特定属性和事件,以保持ViewModel的独立性。

解决方法:可以通过在ViewModel中添加相应的属性和命令,然后将其与控件的属性和事件进行绑定。

为了遵守MVVM模式,我们应该通过命令绑定来处理用户交互,避免在ViewModel中直接调用视图相关的功能,以及尽量避免在XAML中直接使用控件的特定属性和事件。通过这些方法,我们可以更好地遵守MVVM模式,实现代码的重用和解耦。

0
0 Comments

MVVM违规问题的出现原因是开发者在处理UI逻辑时没有遵循MVVM的原则,导致代码冗余和耦合度高。解决方法是将UI逻辑与业务逻辑分离,确保每个UI元素都有独立的命令和绑定。

首先,开发者应该避免在代码中处理UI元素的点击事件,并根据具体的UI元素来执行相应的命令。例如,一个点击了图片的事件和一个点击了数据表格行的事件所代表的意义是不同的,应该分别触发不同的命令。开发者应该将UI元素的命令和绑定放在其个体上,而不是在整个布局层面上设置命令。

其次,开发者应该避免在ViewModel中处理业务逻辑时需要传递事件参数的情况。ViewModel应该通过数据绑定来处理与数据表格的交互,而不需要通过事件参数来判断是否取消或继续更新操作。开发者应该思考如何在不知道具体事件参数的情况下取消数据库操作,并确保在启动操作后仍能进行取消操作。

为了避免MVVM违规问题,开发者应该将UI逻辑和业务逻辑分离,确保每个UI元素都有独立的命令和绑定,并通过数据绑定来处理与ViewModel的交互,避免使用事件参数来处理业务逻辑。这样可以使代码更清晰、可维护性更高。

0
0 Comments

MVVM Violations 是指在MVVM(Model-View-ViewModel)架构中出现的问题。下面是出现该问题的原因和解决方法:

1) 使用服务违反了MVVM。在一篇名为 "Implementing Dialog Boxes in MVVM" 的文章中,作者详细阐述了这个问题。他提出了一个“纯净”的解决方案,解决了MVVM对话框的整体问题。实施起来非常简单,类似于数据模板,支持多项目设计,并且可以与第三方库一起使用。

2) 如果使用MVVM Lite,可以使用EventToCommand来指定参数转换器。以下是一个示例,其中使用EventToCommand将窗口鼠标移动消息参数转换为视图模型中的等效表示:


    

3) 如果理解问题正确,可以将视图和视图模型项目都添加为引用,至少在这个项目结构下是这样的。但老实说,我通常将视图和视图模型放在同一个项目中,例如MyProject.UI,按类别文件夹进行整理。我在一家国际公司的合同项目中看到过这种做法,实际上效果非常好,因为你通常会同时编辑视图和对应的视图模型;在解决方案窗口中将它们并排放置确实可以让整个开发过程更容易。显然,有些人不太喜欢这种做法,但我个人认为只要严格遵守MVVM架构,将它们放在同一个项目中并不违反MVVM。而且在单元测试等需要仅创建视图模型的情况下,我从未遇到过任何问题。

将视图和视图模型放在同一个项目中肯定不违反任何MVVM概念。有些人喜欢有一个项目专门用于视图,另一个项目专门用于视图模型,但是个人而言,我的项目是按模块级别而不是按视图/视图模型级别进行组织的。

0