MVVM与工作流集成示例

在现代软件开发中,MVVM(Model-View-ViewModel)架构因其清晰的分层和数据绑定特性而受到青睐。本文将探讨如何在MVVM架构的WPF(Windows Presentation Foundation)应用程序中集成工作流,并使用ExpandoObject实现数据绑定。

MVVM架构简介

MVVM架构的核心在于分层和数据绑定。期望GUI元素能够通过声明式数据绑定来展示工作流的状态,同时最小化或完全避免编码式的命令,以促进层次化的分离关注点。

工作流数据

工作流框架(WF)允许通过Dictionary对象在工作流框架内外传递数据。虽然活动类可以通过WF命令访问Dictionary的元素,但这些元素并不适合WPF数据绑定。过去有一些文章展示了如何将WF数据上下文与WPF DataContext连接起来,以及如何使用WorkflowApplication的Extensions属性将Model注入工作流。这允许访问Model中的属性,并且可以引发事件,ViewModel可以订阅这些事件。但是,自从.NET 4.0及更高版本中添加了Dynamic特性后,就有了一个更简单的机制。

ExpandoObject

.NET 4.0中引入的ExpandoObject是一个动态类,允许在运行时添加属性,并且这些属性通过INotifyPropertyChanged接口自动可用于WPF数据绑定。这使得它成为工作流和WPF视图之间的理想连接。WPF元素可以在编译时绑定到ExpandoObject的属性,即使该属性尚未声明(假设WPF DataContext绑定到ExpandoObject)。稍后,当属性在运行时在ExpandoObject中实例化时,WPF绑定立即生效。

C# using System.Dynamic; ... dynamic Properties = new ExpandoObject(); // more statements Properties.demo = "this property is added at runtime";

现在Properties对象包含一个在运行时定义的字符串属性demo,它自动实现了更改通知。如果demo属性通过数据绑定在XAML中绑定到Label元素的Content属性,那么当执行赋值语句时,Label的内容将立即设置为"this property is added at runtime"。即使在编译XAML时不存在demo属性,也会发生这种情况。在内部,ExpandoObject是一个Dictionary,并且可以容纳各种类型,包括委托。这允许具有对ExpandoObject访问权限的工作流活动引发事件,并创建、设置和获取与GUI绑定的属性,而无需依赖GUI。

将WF与ExpandoObject连接

WF的WorkflowApplication有一个Extensions属性,通过该属性可以将对象注入到WF框架中,并使其对活动可用。这与将参数传递给工作流的机制不同。在这里,Properties ExpandoObject被注入到WorkflowApplication的Extensions属性中,然后启动工作流。

C# Activity activity = new ActivityLibrary1.Activity1(); WorkflowApplication workflow = new WorkflowApplication(activity); // Inject the ExpandoObject into the workflow via the Extensions property. workflow.Extensions.Add(Properties); workflow.Run();

在Activity中,可以通过活动上下文参数的类型检索Extensions属性中的对象。请注意,局部引用对象是dynamic,但搜索的类型是ExpandoObject。在这段代码中,活动是NativeActivity,但相同的技术也适用于CodeActivity。

protected override void Execute(NativeActivityContext context) { dynamic extensionObj = context.GetExtension(); // rest of code extensionObj.label1text = "This is label 1 text"; }

有了对ExpandoObject的访问,可以创建并设置属性。此外,可以调用委托。由于消费ViewModel可能尚未创建这样的委托,因此需要测试它。在这个示例中,委托是一个具有字符串参数的Action委托。与所有ExpandoObject成员一样,模板是。必须将ExpandoObject转换为IDictionary类型,以测试它是否具有键(AddList)的委托。如果直接测试AddList成员,ExpandoObject将抛出RuntimeBinderException。ExpandoObjects上的属性可以通过赋值自动创建,但不能通过访问创建。请记住,在内部,它们是通过Dictionary实现的。ExpandoObjects有点棘手!

示例应用程序

示例应用程序展示了这些概念。工作流被创建为一个库(DLL),并且不依赖应用程序的任何GUI方面。可绑定元素是两个标签和一个列表框。一个Action委托弹出一个MessageBox对话框,另一个将其字符串参数添加到绑定到列表框的ObservableCollection。Grid的DataContext设置为MainWindow构造函数中的ExpandoObject "Properties"。

必须使用Dispatcher调用Action委托,因为调用它们的活动在工作流线程上运行。NativeActivity1暂停2秒钟以模拟工作。应用程序一旦编译并运行,就会显示一个带有"Start Workflow"按钮和可见列表框的窗口。两个标签在程序启动时不可见,因为它们没有内容。当点击按钮时,点击处理程序调用ViewModel方法,该方法创建工作流,注入ExpandoObject,并启动工作流。在这个小示例中,按钮点击是在点击处理程序中处理的,而不是在Command中。ViewModel没有依赖于View。

两个工作流活动填充标签并将字符串添加到列表框。标签绑定到尚未创建的Properties ExpandoObject的属性;一旦创建属性,标签的内容就会立即显示。ObservableCollection "list"被分配给Properties.items属性,该属性绑定到列表框的ItemSource。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485