作法:建立自訂活動設計工具
通常實作自訂活動設計工具的方式,是讓其相關聯活動能夠透過其他活動組合,這些活動的設計工具能夠隨著活動放到設計介面上。 若要執行這項功能,自訂活動設計工具必須提供可放置任意活動的「拖放區域」,以及可供管理設計介面上所產生的項目集合之方法。 本主題說明如何建立包含這種卸除區的自訂活動設計工具,以及如何建立能夠提供管理設計工具項目集合所需之編輯功能的自訂活動設計工具。
自訂活動設計工具通常繼承自 ActivityDesigner,它是任何沒有特定設計工具之活動的預設基底活動設計工具型別。 這個型別提供與屬性方格互動及設定管理色彩和圖示等基本層面等的設計階段經驗。
ActivityDesigner 會使用兩項 Helper 控制項 (WorkflowItemPresenter 和 WorkflowItemsPresenter) 來簡化自訂活動設計工具的開發。 這些 Helper 能夠處理拖放子項目、刪除、選取及加入子項目之類的常見功能。 WorkflowItemPresenter 允許內含單一子 UI 元素 (假設為「拖放區域」),而 WorkflowItemsPresenter 可提供支援多個 UI 元素,包含排列順序、移動、刪除和加入子元素等額外功能。
其他需要在自訂活動設計工具實作中強調的重要部分,關係到如何使用 WPF 資料繫結將視覺化編輯繫結至我們在設計工具中所編輯內容之記憶體內預存的執行個體。 這項操作可透過模型項目樹狀完成,該樹狀也負責進行變更通知,以及追蹤如狀態變更這類事件。
本主題將說明兩種程序。
第一種程序描述如何使用提供接收其他活動之卸除區的 WorkflowItemPresenter 建立自訂活動設計工具。 此程序以自訂複合設計工具 - 工作流程項目簡報者範例為基礎。
第二種程序描述如何使用提供編輯所包含項目集合時需要之功能的 WorkflowItemsPresenter 建立自訂活動設計工具。 此程序以自訂複合設計工具 - 工作流程項目簡報者範例為基礎。
若要使用 WorkflowItemPresenter 建立含有卸除區的自訂活動設計工具
啟動 Visual Studio 2010。
在 [檔案] 功能表上,指向 [新增],然後選取 [專案]。
[ 新增專案 ] 對話方塊隨即開啟。
在 [已安裝的範本] 窗格中,從偏好的語言類別中選取 [Windows] 。
在 [範本] 窗格中,選取 [WPF 應用程式] 。
在 [名稱] 方塊中,輸入
UsingWorkflowItemPresenter
。在 [位置] 方塊中,輸入用於儲存專案的目錄,或按一下 [瀏覽] 以瀏覽至該目錄。
在 [解決方案] 方塊中,接受預設值。
按一下 [確定]。
以滑鼠右鍵按一下 [方案總管] 中的 MainWindows.xaml 檔案,然後選取 [刪除],並確認 [Microsoft Visual Studio] 對話方塊中的 [確定]。
在 [方案總管] 中以滑鼠右鍵按一下 [UsingWorkflowItemPresenter] 專案,依序選取 [加入] 和 [新增項目...] 以顯示 [加入新項目] 對話方塊,然後從左側的 [已安裝的範本] 區段中選取 [WPF] 類別。
選取 [視窗 (WPF)] 範本,命名為
RehostingWFDesigner
,然後按一下 [加入]。開啟 RehostingWFDesigner.xaml 檔案,將下列程式碼貼入其中,以定義應用程式的 UI:
<Window x:Class=" UsingWorkflowItemPresenter.RehostingWFDesigner" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sapt="clr-namespace:System.Activities.Presentation.Toolbox;assembly=System.Activities.Presentation" xmlns:sys="clr-namespace:System;assembly=mscorlib" Title="Window1" Height="600" Width="900"> <Window.Resources> <sys:String x:Key="AssemblyName">System.Activities, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35</sys:String> </Window.Resources> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="2*"/> <ColumnDefinition Width="7*"/> <ColumnDefinition Width="3*"/> </Grid.ColumnDefinitions> <Border Grid.Column="0"> <sapt:ToolboxControl Name="Toolbox"> <sapt:ToolboxCategory CategoryName="Basic"> <sapt:ToolboxItemWrapper AssemblyName="{StaticResource AssemblyName}" > <sapt:ToolboxItemWrapper.ToolName> System.Activities.Statements.Sequence </sapt:ToolboxItemWrapper.ToolName> </sapt:ToolboxItemWrapper> <sapt:ToolboxItemWrapper AssemblyName="{StaticResource AssemblyName}"> <sapt:ToolboxItemWrapper.ToolName> System.Activities.Statements.WriteLine </sapt:ToolboxItemWrapper.ToolName> </sapt:ToolboxItemWrapper> <sapt:ToolboxItemWrapper AssemblyName="{StaticResource AssemblyName}"> <sapt:ToolboxItemWrapper.ToolName> System.Activities.Statements.If </sapt:ToolboxItemWrapper.ToolName> </sapt:ToolboxItemWrapper> <sapt:ToolboxItemWrapper AssemblyName="{StaticResource AssemblyName}"> <sapt:ToolboxItemWrapper.ToolName> System.Activities.Statements.While </sapt:ToolboxItemWrapper.ToolName> </sapt:ToolboxItemWrapper> </sapt:ToolboxCategory> </sapt:ToolboxControl> </Border> <Border Grid.Column="1" Name="DesignerBorder"/> <Border Grid.Column="2" Name="PropertyBorder"/> </Grid> </Window>
若要關聯活動設計工具與活動型別,您必須在中繼資料存放區中註冊該活動設計工具。 若要執行這項操作,請將
RegisterMetadata
方法加入至RehostingWFDesigner
類別。 在RegisterMetadata
方法的範圍內建立 AttributeTableBuilder 物件,並呼叫 AddCustomAttributes 方法以加入屬性。 呼叫 AddAttributeTable 方法,將 AttributeTable 加入至中繼資料存放區。 下列程式碼包含設計工具的重新裝載邏輯。 它會註冊中繼資料,將SimpleNativeActivity
放入工具箱,然後建立工作流程。 將此程式碼放入 RehostingWFDesigner.xaml.cs 檔案。using System; using System.Activities.Core.Presentation; using System.Activities.Presentation; using System.Activities.Presentation.Metadata; using System.Activities.Presentation.Toolbox; using System.Activities.Statements; using System.ComponentModel; using System.Windows; namespace UsingWorkflowItemPresenter { // Interaction logic for RehostingWFDesigner.xaml public partial class RehostingWFDesigner { public RehostingWFDesigner() { InitializeComponent(); } protected override void OnInitialized(EventArgs e) { base.OnInitialized(e); // Register metadata. (new DesignerMetadata()).Register(); RegisterCustomMetadata(); // Add custom activity to toolbox. Toolbox.Categories.Add(new ToolboxCategory("Custom activities")); Toolbox.Categories[1].Add(new ToolboxItemWrapper(typeof(SimpleNativeActivity))); // Create the workflow designer. var wd = new WorkflowDesigner(); wd.Load(new Sequence()); DesignerBorder.Child = wd.View; PropertyBorder.Child = wd.PropertyInspectorView; } void RegisterCustomMetadata() { var builder = new AttributeTableBuilder(); builder.AddCustomAttributes(typeof(SimpleNativeActivity), new DesignerAttribute(typeof(SimpleNativeDesigner))); MetadataStore.AddAttributeTable(builder.CreateTable()); } } }
以滑鼠右鍵按一下 [方案總管] 中的 [References] 目錄,並選取 [加入參考...] 以顯示 [加入參考] 對話方塊。
按一下 [.NET] 索引標籤,尋找名為 [System.Activities.Core.Presentation] 的組件,然後選取該組件並按一下 [確定]。
使用相同的程序將參考加入至下列組件:
System.Data.DataSetExtensions.dll
System.Activities.Presentation.dll
System.ServiceModel.Activities.dll
開啟 [App.xaml] 檔案,並將 StartUpUri 的值變更為「RehostingWFDesigner.xaml」。
在 [方案總管] 中以滑鼠右鍵按一下 UsingWorkflowItemPresenter 專案,依序選取 [加入] 和 [新增項目...] 以顯示 [加入新項目] 對話方塊,然後從左側的 [已安裝的範本] 區段中選取 [工作流程] 類別。
選取 [活動設計工具] 範本,命名為
SimpleNativeDesigner
,然後按一下 [加入]。開啟 SimpleNativeDesigner.xaml 檔案,並將下列程式碼貼入其中。 請注意,這個程式碼會使用 ActivityDesigner 做為根項目,並且示範如何使用繫結將 WorkflowItemPresenter 整合至設計工具中,以便在複合活動設計工具中顯示子型別。
注意
ActivityDesigner 的結構描述允許只將一個子項目加入自訂活動設計工具定義中,不過,這個項目可以是
StackPanel
、Grid
,也可以是其他複合 UI 項目。<sap:ActivityDesigner x:Class=" UsingWorkflowItemPresenter.SimpleNativeDesigner" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation" xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation"> <sap:ActivityDesigner.Resources> <DataTemplate x:Key="Collapsed"> <StackPanel> <TextBlock>This is the collapsed view</TextBlock> </StackPanel> </DataTemplate> <DataTemplate x:Key="Expanded"> <StackPanel> <TextBlock>Custom Text</TextBlock> <sap:WorkflowItemPresenter Item="{Binding Path=ModelItem.Body, Mode=TwoWay}" HintText="Please drop an activity here" /> </StackPanel> </DataTemplate> <Style x:Key="ExpandOrCollapsedStyle" TargetType="{x:Type ContentPresenter}"> <Setter Property="ContentTemplate" Value="{DynamicResource Collapsed}"/> <Style.Triggers> <DataTrigger Binding="{Binding Path=ShowExpanded}" Value="true"> <Setter Property="ContentTemplate" Value="{DynamicResource Expanded}"/> </DataTrigger> </Style.Triggers> </Style> </sap:ActivityDesigner.Resources> <Grid> <ContentPresenter Style="{DynamicResource ExpandOrCollapsedStyle}" Content="{Binding}" /> </Grid> </sap:ActivityDesigner>
在 [方案總管] 中以滑鼠右鍵按一下 UsingWorkflowItemPresenter 專案,依序選取 [加入] 和 [新增項目...] 以顯示 [加入新項目] 對話方塊,然後從左側的 [已安裝的範本] 區段中選取 [工作流程] 類別。
選取 [活動設計工具] 範本,命名為
SimpleNativeActivity
,然後按一下 [加入]。將下列程式碼輸入 SimpleNativeActivity.cs 檔案中,以實作
SimpleNativeActivity
類別:using System.Activities; namespace UsingWorkflowItemPresenter { public sealed class SimpleNativeActivity : NativeActivity { // this property contains an activity that will be scheduled in the execute method // the WorkflowItemPresenter in the designer is bound to this to enable editing // of the value public Activity Body { get; set; } protected override void CacheMetadata(NativeActivityMetadata metadata) { metadata.AddChild(Body); base.CacheMetadata(metadata); } protected override void Execute(NativeActivityContext context) { context.ScheduleActivity(Body); } } }
從 [組建] 功能表中選取 [組建解決方案]。
從 [偵錯] 功能表中選取 [啟動但不偵錯],以開啟重新裝載的自訂設計視窗。
若要使用 WorkflowItemsPresenter 建立自訂活動設計工具
第二種自訂活動設計工具的程序與第一種幾乎相同,但有幾處修改:首先是將第二個應用程式命名為
UsingWorkflowItemsPresenter
。 此外,這個應用程式不會定義新的自訂活動。主要的差異包含在 CustomParallelDesigner.xaml 和 RehostingWFDesigner.xaml.cs 檔案中。 以下為 CustomParallelDesigne.xaml 檔案中定義 UI 的程式碼:
<sap:ActivityDesigner x:Class=" UsingWorkflowItemsPresenter.CustomParallelDesigner" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation" xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation"> <sap:ActivityDesigner.Resources> <DataTemplate x:Key="Collapsed"> <TextBlock>This is the Collapsed View</TextBlock> </DataTemplate> <DataTemplate x:Key="Expanded"> <StackPanel> <TextBlock HorizontalAlignment="Center">This is the</TextBlock> <TextBlock HorizontalAlignment="Center">extended view</TextBlock> <sap:WorkflowItemsPresenter HintText="Drop Activities Here" Items="{Binding Path=ModelItem.Branches}"> <sap:WorkflowItemsPresenter.SpacerTemplate> <DataTemplate> <Ellipse Width="10" Height="10" Fill="Black"/> </DataTemplate> </sap:WorkflowItemsPresenter.SpacerTemplate> <sap:WorkflowItemsPresenter.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Horizontal"/> </ItemsPanelTemplate> </sap:WorkflowItemsPresenter.ItemsPanel> </sap:WorkflowItemsPresenter> </StackPanel> </DataTemplate> <Style x:Key="ExpandOrCollapsedStyle" TargetType="{x:Type ContentPresenter}"> <Setter Property="ContentTemplate" Value="{DynamicResource Collapsed}"/> <Style.Triggers> <DataTrigger Binding="{Binding Path=ShowExpanded}" Value="true"> <Setter Property="ContentTemplate" Value="{DynamicResource Expanded}"/> </DataTrigger> </Style.Triggers> </Style> </sap:ActivityDesigner.Resources> <Grid> <ContentPresenter Style="{DynamicResource ExpandOrCollapsedStyle}" Content="{Binding}"/> </Grid> </sap:ActivityDesigner>
以下為 RehostingWFDesigner.xaml.cs 檔案中提供重新裝載邏輯的程式碼:
using System; using System.Activities.Core.Presentation; using System.Activities.Presentation; using System.Activities.Presentation.Metadata; using System.Activities.Statements; using System.ComponentModel; using System.Windows; namespaceUsingWorkflowItemsPresenter { public partial class RehostingWfDesigner : Window { public RehostingWfDesigner() { InitializeComponent(); } protected override void OnInitialized(EventArgs e) { base.OnInitialized(e); // Register metadata. (new DesignerMetadata()).Register(); RegisterCustomMetadata(); // Create the workflow designer. var wd = new WorkflowDesigner(); wd.Load(new Sequence()); DesignerBorder.Child = wd.View; PropertyBorder.Child = wd.PropertyInspectorView; } void RegisterCustomMetadata() { var builder = new AttributeTableBuilder(); builder.AddCustomAttributes(typeof(Parallel), new DesignerAttribute(typeof(CustomParallelDesigner))); MetadataStore.AddAttributeTable(builder.CreateTable()); } } }