为 WF 自定义活动属性添加设计时支持






4.25/5 (4投票s)
本文展示了我们如何轻松地为 WF 自定义活动属性添加设计时支持
引言
有时,当我们开发 WF 自定义活动时,我们希望拥有“属性设计时”支持,以加快属性的设置过程。如果您为一个自定义活动定义了一个属性,您可以提供一个自定义用户界面或类型编辑器,通过属性浏览器来编辑该属性的值。您可以构建一个名为“设计器”的类,该类可以在设计时管理组件或控件外观和行为的各个方面。
Using the Code
在这种情况下,我们将创建一个不太有用的自定义活动,只是为了展示属性设计时支持的工作原理。首先,我们将创建一个顺序工作流控制台应用程序。我们将使用此项目来测试我们的自定义活动。然后,我们必须添加一个包含自定义活动的 WorkFlow
库项目。
- 导航至 开始 | 所有程序 | Microsoft Visual Studio 2005 | Microsoft Visual Studio 2005。
- 选择 文件 | 新建 | 项目菜单命令。
- Visual Studio 将显示“新建项目”对话框。
- 选择 Visual C# | Workflow 项目类型。
- 选择 顺序工作流控制台应用程序。
- 右键单击解决方案。
- 选择 添加新项目。
- 单击 Workflow | Workflow Library。
此时,我们应该有一个类似这样的结果

第一步是设置自定义活动的基础类。在此示例中,我们创建一个简单的自定义活动,因此我们必须将 System.Workflow.ComponentModel.Activity
设置为活动的基类。要做到这一点,只需单击活动属性窗口,然后单击基类属性。将会弹出一个窗口,然后选择 Activity 作为类型名称。

此时,活动的外观应如上图所示

现在我们准备开始向活动添加代码。在此示例中,我们创建一个打印文件路径属性到屏幕上的活动。这是一个完全无用的活动,但它是展示属性设计支持如何工作的绝佳示例。要开始,我们必须向我们的活动添加属性。在此情况下,我们只创建一个属性来包含文件的文件路径。在活动的 कोड 视图中,添加以下代码
using System.ComponentModel;
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Linq;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
namespace CustomActivityTester
{
public partial class MyCustomActivity : System.Workflow.ComponentModel.Activity
{
public MyCustomActivity()
{
InitializeComponent();
}
public static DependencyProperty FilePathProperty =
System.Workflow.ComponentModel.DependencyProperty.Register(
"FilePath", typeof(string), typeof(MyCustomActivity));
[Description("FilePath")]
[Category("MyCustomActivity")]
[Browsable(true)]
[DefaultValueAttribute("False")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public string FilePath
{
get
{
return ((string)base.GetValue(MyCustomActivity.FilePathProperty));
}
set
{
base.SetValue(MyCustomActivity.FilePathProperty, value);
}
}
}
}
现在我们可以将自定义活动添加到 Visual Studio 工具箱。我们还没有完成开发,但这样我们可以一步一步地看到它的工作原理。
- 右键单击工具箱。
- 选择“选择项”。
- 点击浏览选项卡。
- 从自定义活动项目文件夹中选择 myCustomLibrary.dll。
此时,我们的活动应该出现在工具箱中

现在将活动拖放到工作流上。

选择活动并单击属性窗口。我们可以看到我们创建的 filePath
属性。Visual Studio 提供了设置属性的标准方法。我们可以通过代码设置它,或者我们可以创建一个属性或字段来绑定属性,然后我们可以通过代码再次设置它。
this.myCustomActivity1.FilePath = @"c:\MyFile.txt";
或者

现在,如果我们想加快这项任务,我们可以为 FilePath
属性添加设计支持。也许在这种情况下,这并不是真正必要的,因为我们只需要设置一个文件路径,但这只是一个展示此过程如何工作的示例。属性设置的 UI 基于一个简单的 Winform,因此作为第一步,我们必须创建一个 Winform,我们在其中设计界面,并在其中添加代码来设置我们的属性。要做到这一点,右键单击 MyCustomLibrary
项目,然后向项目添加一个名为“FilePathDesignSupport
”的新窗口窗体。

现在,为了避免用户在设置 FilePath
属性时关闭该窗口窗体并调整大小,我们需要设置几个窗体属性。
- 设置
ControlBox=false
。 - 设置
FormBorderStyle="FixedSingle"
。
现在我们可以开始设计窗口窗体,添加设置属性所需的控件
- 添加一个名为
btnCancel
的按钮 - 添加一个名为
btnOk
的按钮 - 添加一个名为
btnBrowse
的按钮 - 添加一个名为
lblFileName
的标签 - 添加一个名为
lblFileSelected
的标签
将此代码添加到窗体的代码中
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace MyCustomLibrary
{
public partial class FilePathDesignSupport: Form
{
public FilePathDesignSupport()
{
InitializeComponent();
}
private string _fileName = string.Empty;
public string FileName
{
get
{
return _fileName;
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
this.lblFileSelected.Text = string.Empty;
this._fileName = string.Empty;
this.Close();
}
private void btnOk_Click(object sender, EventArgs e)
{
this.Close();
}
private void btnBrowse_Click(object sender, EventArgs e)
{
this.openFileDialog1.ShowDialog();
}
private void openFileDialog1_FileOk(object sender, CancelEventArgs e)
{
if (string.IsNullOrEmpty(this.openFileDialog1.FileName) == false)
{
this.lblFileSelected.Text = this.openFileDialog1.FileName;
this._fileName = this.lblFileSelected.Text;
}
else
{
this.lblFileSelected.Text = string.Empty;
this._fileName = string.Empty;
}
}
}
}
现在,用于设置 FilePath
属性的 UI 已经准备就绪。下一步是创建一个类来“管理”我们之前创建的 UI 的可视化,然后我们必须添加一个属性来告诉 Visual Studio 设计器,当用户想要设置属性时显示哪个控件。“UI 管理器”由一个继承自“UITypeEditor
”的类表示。
下面是如何实现该类的
using System.ComponentModel;
using System;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Linq;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using System.Drawing.Design;
using MyCustomLibrary;
namespace CustomActivityTester
{
public partial class MyCustomActivity : System.Workflow.ComponentModel.Activity
{
public MyCustomActivity()
{
InitializeComponent();
}
public static DependencyProperty FilePathProperty =
System.Workflow.ComponentModel.DependencyProperty.Register(
"FilePath", typeof(string), typeof(MyCustomActivity));
[Description("FilePath")]
[Category("MyCustomActivity")]
[Browsable(true)]
[DefaultValueAttribute("False")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Editor(typeof(DriveEditor), typeof(UITypeEditor))]
public string FilePath
{
get
{
return ((string)base.GetValue(MyCustomActivity.FilePathProperty));
}
set
{
base.SetValue(MyCustomActivity.FilePathProperty, value);
}
}
protected override ActivityExecutionStatus Execute
(ActivityExecutionContext executionContext)
{
Console.WriteLine(string.Concat("The File path is: ",this.FilePath));
return ActivityExecutionStatus.Closed;
}
}
public class DriveEditor : UITypeEditor
{
public override System.Drawing.Design.UITypeEditorEditStyle
GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
{
// We will use a window for property editing.
return UITypeEditorEditStyle.Modal;
}
public override object EditValue(
System.ComponentModel.ITypeDescriptorContext context,
System.IServiceProvider provider, object value)
{
FilePathDesignSupport frm = new FilePathDesignSupport();
//Show the UI to set up the property
frm.ShowDialog();
// Return the file name of the file selected.
return frm.FileName;
}
public override bool GetPaintValueSupported(
System.ComponentModel.ITypeDescriptorContext context)
{
// No special thumbnail will be shown for the grid.
return false;
}
}
}
UITypeEditor
类最重要的一个方法是 EditValue
方法。它告诉 Visual Studio 当用户单击属性窗口以设置属性时应该做什么。在这种情况下,我们创建 FilePathDesignSupport
窗体的一个实例,然后将其显示出来。此方法必须返回一个对象,该对象表示我们正在设置的属性的值。在这种情况下,我们返回所选文件的文件路径。之后,我们必须将“FilePath
”属性“绑定”到表示要显示的 UI 的类。要做到这一点,我们只需在 FilePath
属性中添加此属性 [Editor(typeof(DriveEditor), typeof(UITypeEditor))]
。此时,一切都完成了。如果我们单击工作流中的自定义活动,然后单击 FilePath
属性,将显示 FilePath
窗体来设置属性。最后,我们可以覆盖 Activity
类的 Execute method
。这是包含实现活动行为的代码的方法。在工作流执行活动时,运行时会调用此方法。在这种情况下,我们只是在屏幕上打印 FilePath
属性的值。

正如我们在本文中看到的,为自定义活动属性添加设计支持相当容易。我们可以每次想加快属性设置过程时都使用这种方式,或者我们想帮助用户设置属性。