wpf的棱镜vs mvvm灯
Posted
技术标签:
【中文标题】wpf的棱镜vs mvvm灯【英文标题】:prism vs mvvm light for wpf 【发布时间】:2013-12-27 13:02:27 【问题描述】:我们正在启动一个带有 MVVM 项目的 WPF,并且必须决定使用 PRISM 或 MVVM Light(我对这两个框架都是新手)。我已经阅读了一些帖子,但仍有一些问题。有人可以对以下方面进行一些说明吗?两个框架?:
性能:无论出于何种原因,其中一个框架的性能是否优于另一个?
应用程序内的通信(viewmodel 到 viewmodel 或模块之间等):我读过 MVVM Light 具有消息服务,这似乎也相当容易。但 PRISM 似乎没有任何等价物。真的吗? PRISM 将如何处理交互?
单元测试:已阅读 PRISM 更好地支持单元测试。我们还能在 MVVM Light 中编写 NUNIT 或 VSTS 测试吗?
【问题讨论】:
回答您的 2):Prism 有一个 EventAggregator,它执行您描述的 MVVM 所做的事情。 除了emedbo的评论,您可以在Loosely Coupled Communication的Prism指南章节中找到更多Prism交流的相关信息 MSDN. PRISM 的最佳功能之一是Regions
。它有EventAggregator
用于ViewModel
到ViewModel
通讯。您可以使用混合行为(System.Windows.Interactivity、Microsoft.Expression.Interactions)进行交互。单元测试取决于您编写ViewModel
单元测试的友好程度,而不是取决于您使用的 MVVM 框架。因此,如果您确实希望在您的应用程序中支持Region
,那么请使用 PRISM,否则使用 MVVM-Light。不知道有没有办法也可以用 MVVM-Light 实现 Regions。
【参考方案1】:
我刚刚将一个项目从 Prism 转移到 MvvmLight,它似乎工作得更快(非常主观)。
Prism 和 MvvmLight 都有 Mediator 实现(Prism 中的 IEventAggregator,MvvmLight 中的 IMessenger)。但与 IEventAggregator 相比,IMessenger 具有更多功能(例如,使用令牌发送消息)并且使用起来更加方便(参见下一项)。
MvvmLight 还有一个更强大的 ViewModelBase 类。
使用 MvvmLight 的应用程序比使用 Prism 的应用程序更容易测试。例如,IMessenger 比 IEventAggregator 更容易模拟。
PrismViewModel.cs
using System;
using Microsoft.Practices.Prism.Events;
using Microsoft.Practices.Prism.ViewModel;
// An ugly empty event class
public class StringEvent : CompositePresentationEvent<string>
public sealed class PrismViewModel : NotificationObject
private readonly IEventAggregator _eventAggregator;
private string _name;
public PrismViewModel(IEventAggregator eventAggregator)
if (eventAggregator == null)
throw new ArgumentNullException("eventAggregator");
_eventAggregator = eventAggregator;
_eventAggregator.GetEvent<StringEvent>().Subscribe(s => Name = s);
public string Name
get return _name;
set
// boiler-plate code
if (value == _name)
return;
_name = value;
RaisePropertyChanged(() => Name);
public void SendMessage(string message)
_eventAggregator.GetEvent<StringEvent>().Publish(message);
PrismViewModelTestCase.cs
using System;
using FluentAssertions;
using Microsoft.Practices.Prism.Events;
using NSubstitute;
using NUnit.Framework;
public class PrismViewModelTestCase
private static PrismViewModel CreateViewModel(IEventAggregator eventAggregator = null)
// You can't return Substitute.For<IEventAggregator>()
// because it returns null when PrismViewModel's constructor
// invokes GetEvent<StringEvent>() method which leads to NullReferenceException
return new PrismViewModel(eventAggregator ?? CreateEventAggregatorStub());
private static IEventAggregator CreateEventAggregatorStub()
var eventAggregatorStub = Substitute.For<IEventAggregator>();
eventAggregatorStub.GetEvent<StringEvent>().Returns(Substitute.For<StringEvent>());
return eventAggregatorStub;
[Test]
public void Constructor_WithNonNullEventAggregator_ExpectedSubscribesToStringEvent()
// Arrange
var stringEventMock = Substitute.For<StringEvent>();
var eventAggregatorStub = Substitute.For<IEventAggregator>();
eventAggregatorStub.GetEvent<StringEvent>().Returns(stringEventMock);
// Act
CreateViewModel(eventAggregatorStub);
// Assert
// With constrained isolation framework you can only mock virtual members
// CompositePresentationEvent<TPayload> has only one virtual Subscribe overload with four parameters
stringEventMock.Received()
.Subscribe(Arg.Any<Action<string>>(), Arg.Any<ThreadOption>(), Arg.Any<bool>(),
Arg.Any<Predicate<string>>());
[Test]
public void Name_ExpectedRaisesPropertyChanged()
var sut = CreateViewModel();
sut.MonitorEvents();
sut.Name = "any-value";
sut.ShouldRaisePropertyChangeFor(vm => vm.Name);
[Test]
public void SendMessage_ExpectedPublishesStringEventThroughEventAggregator()
// Arrange
var stringEventMock = Substitute.For<StringEvent>();
var eventAggregatorStub = Substitute.For<IEventAggregator>();
eventAggregatorStub.GetEvent<StringEvent>().Returns(stringEventMock);
var sut = CreateViewModel(eventAggregatorStub);
const string expectedPayload = "any-string-payload";
// Act
sut.SendMessage(expectedPayload);
// Assert
stringEventMock.Received().Publish(expectedPayload);
MvvmLightViewModel.cs
using System;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Messaging;
public sealed class MvvmLightViewModel : ViewModelBase
private string _name;
public MvvmLightViewModel(IMessenger messenger)
if (messenger == null)
throw new ArgumentNullException("messenger");
// ViewModelBase already have field for IMessenger
MessengerInstance = messenger;
MessengerInstance.Register<string>(this, s => Name = s);
public string Name
get return _name;
set Set(() => Name, ref _name, value); // Chic!
public void SendMessage(string message)
MessengerInstance.Send(message);
MvvmLightViewModelTestCase.cs
using System;
using FluentAssertions;
using GalaSoft.MvvmLight.Messaging;
using NSubstitute;
using NUnit.Framework;
public class MvvmLightViewModelTestCase
private static MvvmLightViewModel CreateViewModel(IMessenger messenger = null)
return new MvvmLightViewModel(messenger ?? Substitute.For<IMessenger>());
[Test]
public void Constructor_WithNonNullMessenger_ExpectedRegistersToStringMessage()
var messengerStub = Substitute.For<IMessenger>();
var sut = CreateViewModel(messengerStub);
messengerStub.Received().Register(sut, Arg.Any<Action<string>>());
[Test]
public void Name_ExpectedRaisesPropertyChanged()
var sut = CreateViewModel();
sut.MonitorEvents();
sut.Name = "any-value";
sut.ShouldRaisePropertyChangeFor(vm => vm.Name);
[Test]
public void SendMessage_ExpectedSendsStringMessageThroughMessenger()
var messengerMock = Substitute.For<IMessenger>();
var sut = CreateViewModel(messengerMock);
const string expectedMessage = "message";
sut.SendMessage(expectedMessage);
messengerMock.Received().Send(expectedMessage);
棱镜的缺点:
我认为任何新项目都应该基于现代解决方案和方法。 恕我直言,任何现代 MVVM 框架(如 Catel、Caliburn.Micro、MvvmLight、ReactiveUI)都比 Prism 好得多。
【讨论】:
不再开发棱镜是完全错误的。 是的,现在错了(不久前发布的新版 Prism)。当我回答这个问题时,Prism 的未来相当模糊。但是 IEventAggregator 仍然缺乏可测试性(我的回答仍然相关)。 请注意,Prism 有一个BindableBase
VM 基类,它提供了一个SetProperty()
方法来处理RaisePropertyChanged()
样板,即:名称的设置器将是:set SetProperty(ref _name, value);
。这使得它几乎与 MVVM Light VM 相同【参考方案2】:
我不相信 MS 曾经将 PRISM 推广为“框架”,就像 MVVM Light、Caliburn 等被“宣传”一样。我的理解是,PRISM 总是作为一种“实践”呈现给“世界”。我相信,这仅仅意味着构建应用程序的有组织的方式。由于 PRISM 提供的所有代码,它变得有点令人困惑,人们可以将其视为可用于构建应用程序的“框架”。而且,确实,您可以使用 PRISM 提供的代码来构建您自己的应用程序。但是,在我看来,PRISM 比可用于 MVVM 的“框架”复杂得多,而且学习曲线陡峭,并且可能会“过度杀伤”并使您的应用程序变得比必要的复杂。如果您在构建应用程序时有时间学习最新的“框架”或“实践”,那就太好了!我的经验是,我没有机会学习一些新的“实践”或最新的“框架”,但必须完成工作。在一个理想的世界里,人们希望能够使用最新最好的“框架”或采用最新的“实践”,但有时你只需要坚持你已经知道的并完成它。
【讨论】:
嗨,欢迎来到堆栈溢出。我不确定这是否“回答”了这里的“问题”(也......过度使用“吓人的引号”会使这更难“阅读”;))。原始海报提出了三个非常具体的问题,您的回复中没有解决这些问题。也许你也可以解决这些问题?否则,我会将您在上面写的内容归类为评论而不是答案……这意味着它更正确地放在评论部分(就在原始问题的下方)。现在 - 你还没有足够的代表来发表评论......但如果答案只是评论,它会被评论者迅速删除。 @TarynEast 尚未被删除 =) 你想要我吗?我能。 ;) 注意:您现在有足够的代表将其移至 cmets 部分...【参考方案3】:您无法完全比较 Prism 和 MvvmLight。
尽管 Prism 被称为 MVVM 框架,但 Prism 更多的是关于应用程序架构。实际上,直到 Prism 5 它与 MVVM 无关,并且在 Prism 4.1 和之前的版本中没有 BaseViewModel 类。
Prism 不是 MVVM 框架,它是应用程序框架,它位于更高的位置。 Prism 5 引入了对 MVVM 的一些支持,而 Prism 6 则更进一步。
MVVM 只是 prism 提供解决问题的另一个方面。
这就像比较 Angular 和 Knockout。 AngularJS 管理整个应用程序并定义应用程序代码的结构指南,而使用 KnockoutJS,应用程序结构完全取决于您。 Prism 和 MvvmLight 的情况类似。
Prism 提供了一组设计模式的实现,这些设计模式有助于编写结构良好且可维护的 XAML 应用程序,包括 MVVM、依赖注入、命令、事件聚合等。 Prism 的核心功能是针对这些平台的可移植类库中的共享代码库; WPF、Windows 10 UWP 和 Xamarin 表单。
如果您正在使用 wpf 开发企业级应用程序,我建议您使用 Prism。
请观看有关使用 Prism 简化 MVVM 的网络研讨会。主持人是布赖恩·拉古纳斯: https://www.youtube.com/watch?v=ZfBy2nfykqY
【讨论】:
以上是关于wpf的棱镜vs mvvm灯的主要内容,如果未能解决你的问题,请参考以下文章