如何在工作流活动中使用 CustomPropertyEditor(即使在绑定设置后)






2.83/5 (3投票s)
解决自定义属性编辑器屏幕在设置绑定后不被调用的问题。
引言
本文档对于那些在工作流活动中使用自定义编辑器创建和编辑绑定时遇到麻烦的人会很有用。这里的棘手之处在于使用 Designer 而不是 editor 标签。Designer 类(与属性 [Designer]
一起使用)使得我们可以使用任何类来编辑绑定,即使我们不想使用屏幕。
背景
最近,我和我的团队在开发客户要求的某个功能时遇到了一个大问题。我们的想法是创建一个新的窗口,用于管理工作流活动的绑定,而不是使用 Microsoft 提供的窗口。换句话说,我们想创建一个 CustomPropertyBindingEditor
,用于设置新的绑定并处理已设置绑定的属性。
这个想法很简单,因为很多开发者在那之前已经多次完成过这个任务。所以,我们想:开始吧!第一次尝试,什么也没做,第二次尝试,什么也没做,第三次、第四次、第五次、第二十次……然后我们想:“好吧,事情并不像我们想象的那么简单”。
主要问题是,我们无法使用同一个窗口(编辑器)来设置新绑定和编辑现有绑定。因为当一个属性没有设置绑定时,属性的类型被用来调用编辑器;但当一个属性已经设置了绑定时,用来调用编辑器的类型是 typeof(ActivityBind)
,而不是属性的类型,所以 Microsoft 的编辑器被调用,而不是我们的自定义编辑器。
CustomPropertyBindingEditor
的问题,却没有任何好的答案。只有一个答案帮助我解决了这个问题,并解决了我们(当时)所有的问题。我想提的一件非常重要的事情是,我们曾向 Microsoft 寻求支持来帮助我们解决这个问题,在超过一个月后,他们回复说,开发此功能是不可能的,甚至开发 WWF 的团队也无法开发出某种解决方法。
好吧,这并非不可能,我可以向你保证!
解决方案
解决方案不像我和许多人期望的那么简单,但问题解决了,这才是重要的!
首先,除了你可能想使用的自定义属性绑定编辑器(而不是 Microsoft 的编辑器)之外,还有十二个类必须使用。
在示例解决方案中,有两个项目。第一个项目包含前面提到的类、custompropertybindingeditor
屏幕和一个示例活动。第二个项目有一个示例 sequentialworkflow
来测试 designer 类。
解决方案包括使用 [Designer]
和 [TypeConverter]
属性来指示我们希望自定义属性绑定编辑器用于哪些类和属性。
项目中的示例活动如下所示:
namespace WFProjectCustomPropertyBindingEditor
{
[Designer( typeof( CustomActivityBindDesigner ), typeof( IDesigner ) )]
public partial class CustomPropertyBindingActivityTest: SequenceActivity
{
public CustomPropertyBindingActivityTest()
{
InitializeComponent();
}
public static DependencyProperty PropertyStringProperty =
DependencyProperty.Register( "PropertyString", typeof( string ),
typeof( CustomPropertyBindingActivityTest ) );
[Description( "Description" )]
[Category( "Category" )]
[Browsable( true )]
[DesignerSerializationVisibility( DesignerSerializationVisibility.Visible )]
[TypeConverter( typeof( CustomTypeConverter ) )]
//[Editor(typeof(CustomPropertyBindingEditor), typeof(UITypeEditor))]
public string PropertyString
{
get
{
return ( (string)( base.GetValue
( CustomPropertyBindingActivityTest.PropertyStringProperty ) ) );
}
set
{
base.SetValue( CustomPropertyBindingActivityTest.PropertyStringProperty,
value );
}
}
public static DependencyProperty PropertyListStringProperty =
DependencyProperty.Register( "PropertyListString",
typeof( List<string> ), typeof( CustomPropertyBindingActivityTest ) );
[Description( "Description" )
[Category( "Category" )]
[Browsable( true )]
[DesignerSerializationVisibility( DesignerSerializationVisibility.Visible )]
[TypeConverter( typeof( CustomTypeConverter ) )]
//[Editor(typeof(CustomPropertyBindingEditor), typeof(UITypeEditor))]
public List<string> PropertyListString
{
get
{
return ((List<string>)(base.GetValue
(CustomPropertyBindingActivityTest.PropertyListStringProperty ) ) );
}
set
{
base.SetValue
(CustomPropertyBindingActivityTest.PropertyListStringProperty, value );
}
}
public static DependencyProperty PropertyIntProperty =
DependencyProperty.Register( "PropertyInt", typeof( Int32 ),
typeof( CustomPropertyBindingActivityTest ) );
[DescriptionAttribute( "PropertyInt" )]
[CategoryAttribute( "PropertyInt Category" )]
[BrowsableAttribute( true )]
[DesignerSerializationVisibilityAttribute
( DesignerSerializationVisibility.Visible )]
[TypeConverter( typeof( CustomTypeConverter ) )]
//[Editor(typeof(CustomPropertyBindingEditor), typeof(UITypeEditor))]
public Int32 PropertyInt
{
get
{
return ( (Int32)( base.GetValue
( CustomPropertyBindingActivityTest.PropertyIntProperty ) ) );
}
set
{
base.SetValue
( CustomPropertyBindingActivityTest.PropertyIntProperty, value );
}
}
}
}
类声明上方的 [Designer]
属性表明我们希望在此类中使用 CustomActivityBind
designer;而每个属性上方的 [TypeConverter]
属性告诉 CustomActivityBind
类应为这些属性使用哪个 typeconverter
。
总而言之,如果你想使用你的自定义编辑器,只需在你想使用的类和属性中包含这两个属性即可。但也可以在一个属性中包含 [TypeConverter]
属性,而将其他属性保持不带此标签,这样带有属性的属性将始终使用你的自定义编辑器,而其他属性则使用原始屏幕。
我没有移除属性上的 [Editor]
标签,以说明如果工作流活动像 Windows Forms 那样工作会是怎样的。在 Windows Forms 中,我们只使用 [Editor]
标签来指定我们要为某个属性使用的编辑器,并且这个编辑器总是被使用,无论它是否有值。
项目中类的描述以及每个类的说明如下。
WFProjectCustomBindingPropertyEditor 项目
ComponentChangeDispatcher
- 当值更新时,此类会通过赋值新值来更新属性ActivityBindNamePropertyDescriptor
- 属性 'Name
' 的属性描述符(由TypeConverter
使用)。ActivityBindPathPropertyDescriptor
- 属性 'Value
' 的属性描述符(由TypeConverter
使用)。ActivityBindPropertyDescriptor
- 整个属性(名称、值和描述行)的属性描述符。CustomActivityBindDesigner
- 负责为我们想使用自定义属性绑定编辑器的属性设置编辑器。CustomTypeConverter
- 将ActivityBind
转换为正确格式,以在PropertyGrid
中显示。DynamicPropertyDescriptor
- 继承自PropertyDescriptor
,用于get
和set
属性的值。FilteredPropertyGrid
- 此类的目的是强制属性描述符使用某种类型的编辑器来获取和设置属性的值。Helpers
- 提供辅助函数来解析属性、获取工作流活动等。PropertyDescriptorUtils
- 触发正在编辑的属性的propertydescriptor
类的GetValue
和SetValue
函数。TypeDescritptorContext
- 用作容器,组合了propertydescriptor
、serviceprovider
和包含正在编辑的属性的对象实例。CustomPropertyBindingActivity
- 示例活动,其中声明了 3 个属性来测试功能。CustomPropertyBindingEditor
- 打开自定义属性编辑器并返回新值 (activitybind
)。
WFConsumer 项目
Workflow1
- 示例工作流,其中包含一个活动 (CustomPropertyBindingActivity
) 和 3 个属性,用于绑定到示例活动中的属性。
示例解决方案
本文档附带的示例解决方案是在 Visual Studio 2008 中开发的。要测试此解决方案,只需打开项目。打开 Studio 后,打开 Workflow1
文件,这是用于测试 designer 类的 SequentialWorkflow
。
考虑因素
我要感谢我所有的同事的支持和考虑。
我想特别感谢我的母亲。在我做困难的事情时,她总是支持我!在我开发这个解决方案的那天,晚上 12 点,她说:“我知道你会找到解决方案的,你总是能找到!” 凌晨 3 点,我完成了它,并且运行良好。