程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WF從入門到精通(第十三章):打造自定義活動(二)

WF從入門到精通(第十三章):打造自定義活動(二)

編輯:關於.NET

FtpGetFileActivity類

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Net;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Design;
using System.Workflow.Activities;
using System.Drawing;
namespace FtpActivity
{
  [Designer(typeof(FtpGetFileActivityDesigner), typeof(IDesigner))]
  [ToolboxBitmap(typeof(FtpGetFileActivity), "FtpImage.bmp")]
  [ToolboxItem(typeof(FtpGetFileActivityToolboxItem))]
  [ActivityValidator(typeof(FtpGetFileActivityValidator))]
  public sealed class FtpGetFileActivity : System.Workflow.ComponentModel.Activity
  {
    public static DependencyProperty FtpUrlProperty = DependencyProperty.Register("FtpUrl", typeof(System.String), typeof(FtpGetFileActivity));
    [Description("Please provide the full URL for the file to download.")]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    [ValidationOption(ValidationOption.Required)]
    [Browsable(true)]
    [Category("FTP Parameters")]
    public string FtpUrl
    {
      get
      {
        return ((string)(base.GetValue(FtpGetFileActivity.FtpUrlProperty)));
      }
      set
      {
        Uri tempUri = null;
        if (Uri.TryCreate(value, UriKind.Absolute, out tempUri))
        {
          if (tempUri.Scheme == Uri.UriSchemeFtp)
          {
            base.SetValue(FtpGetFileActivity.FtpUrlProperty, tempUri.AbsoluteUri);
          }
        }
        else
        {
          // Not a valid FTP URI
          throw new ArgumentException("The value assigned to the FtpUrl property is not a valid FTP URI.");
        }
      }
    }
    public static DependencyProperty FtpUserProperty = DependencyProperty.Register("FtpUser", typeof(System.String), typeof(FtpGetFileActivity));
    [Description("Please provide the FTP user account name.")]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    [ValidationOption(ValidationOption.Optional)]
    [Browsable(true)]
    [Category("FTP Parameters")]
    public string FtpUser
    {
      get
      {
        return ((string)(base.GetValue(FtpGetFileActivity.FtpUserProperty)));
      }
      set
      {
        base.SetValue(FtpGetFileActivity.FtpUserProperty, value);
      }
    }
    public static DependencyProperty FtpPasswordProperty = DependencyProperty.Register("FtpPassword", typeof(System.String), typeof(FtpGetFileActivity));
    [Description("Please provide the FTP user account password.")]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    [ValidationOption(ValidationOption.Optional)]
    [Browsable(true)]
    [Category("FTP Parameters")]
    public string FtpPassword
    {
      get
      {
        return ((string)(base.GetValue(FtpGetFileActivity.FtpPasswordProperty)));
      }
      set
      {
        base.SetValue(FtpGetFileActivity.FtpPasswordProperty, value);
      }
    }
    private const string AnonymousUser = "anonymous";
    private const string AnonymousPassword = "[email protected]";
     protected override ActivityExecutionStatus Execute(
      ActivityExecutionContext executionContext)
    {
      // Retrieve the file.
      GetFile();
      // Work complete, so close.
      return ActivityExecutionStatus.Closed;
    }
    private void GetFile()
    {
      // Create the Uri. We check the validity again
      // even though we checked it in the property
      // setter since binding may have taken place.
      // Binding shoots the new value directly to the
      // dependency property, skipping our local
      // getter/setter logic. Note that if the URL
      // is very malformed, the Uri constructor will
      // throw.
      Uri requestUri = new Uri(FtpUrl);
      if (requestUri.Scheme != Uri.UriSchemeFtp)
      {
        // Not a valid FTP URI
        throw new ArgumentException("The value assigned to the FtpUrl property is not a valid FTP URI.");
      } // if
      string fileName =
        Path.GetFileName(requestUri.AbsolutePath);
      if (String.IsNullOrEmpty(fileName))
      {
        // No file to retrieve.
        return;
      } // if
      Stream bitStream = null;
      FileStream fileStream = null;
      StreamReader reader = null;
      try
      {
        // Open the connection
        FtpWebRequest request =
          (FtpWebRequest)WebRequest.Create(requestUri);
        // Establish the authentication credentials
        if (!String.IsNullOrEmpty(FtpUser))
        {
          request.Credentials =
            new NetworkCredential(FtpUser, FtpPassword);
        } // if
        else
        {
          request.Credentials =
            new NetworkCredential(AnonymousUser,
            !String.IsNullOrEmpty(FtpPassword) ?
            FtpPassword : AnonymousPassword);
        } // else
        // Make the request and retrieve response stream
        FtpWebResponse response =
          (FtpWebResponse)request.GetResponse();
        bitStream = response.GetResponseStream();
        // Create the local file
        fileStream = File.Create(fileName);
        // Read the stream, dumping bits into local file
        byte[] buffer = new byte[1024];
        Int32 bytesRead = 0;
        while ((bytesRead = bitStream.Read(buffer, 0, buffer.Length)) > 0)
        {
          fileStream.Write(buffer, 0, bytesRead);
        } // while
      } // try
      finally
      {
        // Close the response stream
        if (reader != null) reader.Close();
        else if (bitStream != null) bitStream.Close();
        // Close the file
        if (fileStream != null) fileStream.Close();
      } // finally
    }
  }
}

其中接下來要做的一個更重要的事情是創建一個自定義驗證器。盡管你可以使用該FTP活動了,因為它現在已經存在,但此時它是不完整的引入到工作流視圖設計器中的。它所缺少的是屬性驗證。我們就來看看怎樣添加一個驗證器。

創建一個自定義ActivityValidator

現在,我確信你已經看到過小紅色圓圈內包含一個感歎號的標記出現在那些在工作流視圖設計器中沒有完成相應配置的活動中。

例如,在Code活動中假如沒有為它設置ExecuteCode屬性的話將顯示這個指示標記。原因是什麼呢?

答案是活動驗證器強迫這樣做。驗證器檢查和它相關聯的活動的屬性並在需檢查的任何屬性缺失和無效的時候就把錯誤添加進一個錯誤集合中。當設計器的狀態發生改變(換句話說,就是在添加了新活動或者屬性發生改變的時候)以及工作流被編譯的時候會要求驗證器重新對它適用的活動的屬性進行判定。

驗證器能選擇是否對屬性的配置不進行驗證,它也能把它們標記為警告或者是不可接受的錯誤。FTP活動有三個屬性,其中一個很關鍵(就是URL)。其它兩個可以不管,這將產生默認(匿名)用戶的身份驗證。但我們實現我們的驗證器時,我們將把缺少URL的情況(或者在主工作流活動中缺少對URL屬性的綁定)標記為一個錯誤。假如省略了用戶名或密碼的話我們將產生警告信息來提示將使用匿名登錄。

為FtpGetFileActivity工作流活動創建一個驗證器

1.WF中的活動驗證器其實是一個類,因此我們要在FtpActivity項目中添加一個新類。類的名稱命名為“FtpGetFileActivityValidator.cs”。

2.在源文件中添加下面的名稱空間:

using System.Workflow.ComponentModel.Compiler;

3.當創建了FtpGetFileActivityValidator的新類創建後,它是一個private類型的類。而且,WF活動驗證器必須使用ActivityValidator作為基類。因此在源文件中對該類添加public關鍵字以及一個ActivityValicator基類來更改類的定義:

public class FtpGetFileActivityValidator : ActivityValidator

4.為了實際去執行驗證,你必須重寫Validate方法。這裡我們將對屬性進行檢查,假如它們沒有(設置)的話,你將把一個錯誤添加到設計器提供的錯誤集合中。下面是你需要添加到FtpGetFileActivityValidator類中去的完整的Validate重寫方法。

重寫的Validate方法

public override ValidationErrorCollection
  Validate(ValidationManager manager, object obj)
{
  FtpGetFileActivity fget = obj as FtpGetFileActivity;
  if (null == fget)
    throw new InvalidOperationException();
  ValidationErrorCollection errors = base.Validate(manager, obj);
  if (null != fget.Parent)
  {
    // Now actually validate the activity
    if (String.IsNullOrEmpty(fget.FtpUrl) &&
      fget.GetBinding(FtpGetFileActivity.FtpUrlProperty) == null)
    {
      ValidationError err =
        new ValidationError("Note you must specify a URL " +
          "(including filename) for the FTP server.",
          100, false);
      errors.Add(err);
    } // if
    Uri tempUri = null;
    if (Uri.TryCreate(fget.FtpUrl, UriKind.Absolute, out tempUri))
    {
      if (tempUri.Scheme != Uri.UriSchemeFtp)
      {
        ValidationError err =
          new ValidationError("The FTP URL must be set to an" +
             " FTP endpoint.", 101, false);
        errors.Add(err);
      } // if
    } // if
    else if (!String.IsNullOrEmpty(fget.FtpUrl))
    {
      ValidationError err =
        new ValidationError("The FTP URL must be a valid FTP URI.",
           102, false);
      errors.Add(err);
    } // else if
    if (String.IsNullOrEmpty(fget.FtpUser) &&
      fget.GetBinding(FtpGetFileActivity.FtpUserProperty) == null)
    {
      ValidationError err =
        new ValidationError("The 'anonymous' user account will " +
          "be used for logging into the FTP server.", 200, true);
      errors.Add(err);
    } // if
    if (String.IsNullOrEmpty(fget.FtpPassword) &&
      fget.GetBinding(FtpGetFileActivity.FtpPasswordProperty) == null)
    {
      ValidationError err =
        new ValidationError("The default anonymous password " +
          "'[email protected]' will be used for logging " +
           "into the FTP server.", 300, true);
      errors.Add(err);
    } // if
  }
  return errors;
}

5.FtpGetFileActivityValidator類現在就完成了,但我們實際上並沒有通知WF去執行驗證。為此,回到FtpGetFileActivity類中,在該類定義的前面為該類添加下面的特性標記:

[ActivityValidator(typeof(FtpGetFileActivityValidator))]

6.生成FtpActivity項目,修正可能出現的任何錯誤。

完整的驗證器代碼如清單13-2所示。現在,當你拖拽該FtpGetFileActivity到你的工作流中去的時候,假如你忘了指定該URL或者你沒有為提供的URL創建綁定的話,工作流不能編譯。並且,假如你沒有提供用戶名或密碼,或者你甚至沒有在Visual Studio中使用屬性面板對它們進行綁定的話,你將收到警告信息。

清單13-2 FtpGetFileActivityValidator.cs的完整代碼

提供工具箱位圖

FtpGetFileActivityValidator類

using System;
using System.Collections.Generic;
using System.Text;
using System.Workflow.ComponentModel.Compiler;
namespace FtpActivity
{
  public class FtpGetFileActivityValidator : ActivityValidator
  {
    public override ValidationErrorCollection
      Validate(ValidationManager manager, object obj)
    {
      FtpGetFileActivity fget = obj as FtpGetFileActivity;
      if (null == fget)
        throw new InvalidOperationException();
      ValidationErrorCollection errors = base.Validate(manager, obj);
      if (null != fget.Parent)
      {
        // Now actually validate the activity
        if (String.IsNullOrEmpty(fget.FtpUrl) &&
          fget.GetBinding(FtpGetFileActivity.FtpUrlProperty) == null)
        {
          ValidationError err =
            new ValidationError("Note you must specify a URL " +
              "(including filename) for the FTP server.", 100, false);
          errors.Add(err);
        } // if
        Uri tempUri = null;
        if (Uri.TryCreate(fget.FtpUrl, UriKind.Absolute, out tempUri))
        {
          if (tempUri.Scheme != Uri.UriSchemeFtp)
          {
            ValidationError err =
              new ValidationError("The FTP URL must be set to an FTP endpoint.",
                101, false);
            errors.Add(err);
          } // if
        } // if
        else if (!String.IsNullOrEmpty(fget.FtpUrl))
        {
          ValidationError err =
            new ValidationError("The FTP URL must be a valid FTP URI.", 102, false);
          errors.Add(err);
        } // else if
        if (String.IsNullOrEmpty(fget.FtpUser) &&
          fget.GetBinding(FtpGetFileActivity.FtpUserProperty) == null)
        {
          ValidationError err =
            new ValidationError("The 'anonymous' user account will " +
              "be used for logging into the FTP server.", 200, true);
          errors.Add(err);
        } // if
        if (String.IsNullOrEmpty(fget.FtpPassword) &&
          fget.GetBinding(FtpGetFileActivity.FtpPasswordProperty)
          == null)
        {
          ValidationError err =
            new ValidationError("The default anonymous password " +
              "'[email protected]' will be used for logging " +
               "into the FTP server.", 300, true);
          errors.Add(err);
        } // if
      }
      return errors;
    }
  }
}

我們下面將在我們的活動中做的事情是為它提供一個工具箱位圖。這不是一個嚴格意義上的WF任務。這種功能被集成到.NET中,主要用於為Visual Studio設計器提供支持。它也並不難做到。

為FtpGetFileActivity工作流活動指定一個工具箱位圖

1.下載本章的示例代碼,你將找到一個名稱為FtpImage的位圖文件。把FtpImage文件從Windows Explorer窗口中拖拽到FtpActivity項目的樹形控制節點下面,這會把該文件復制並添加到你的項目目錄中。

2.然後,你必須把該位圖作為資源編譯進你的程序集中。在解決方案資源管理器的FtpActivity項目中選中FtpImage文件以激活它的屬性。更改“生成操作”屬性,把它從“編譯”改為“嵌入的資源”。

3.和驗證器一樣,只是把一個位圖編譯進你活動的程序集中是不夠的。你也必須通知Visual Studio該活動有一個相關的工具箱位圖。和先前一樣,你使用一個特性來通知Visual Studio這件事。把下面的特性添加到FtpGetFileActivity類的定義中(就像你在前面一節添加ActivityValidator一樣):

[ToolboxBitmap(typeof(FtpGetFileActivity), "FtpImage.bmp")]

備注:ToolboxBitmapAttribute不是WF所特有的。它可以用到任何的控件。看看http://msdn2.microsoft.com/en-us/library/4wk1wc0a(VS.80).aspx可獲得更多信息。

4.生成FtpActivity項目。不應出現任何錯誤,假如有的話,修正它們。

假如你此刻創建一個順序工作流並把這個活動拖拽到該工作流中去的話,這個活動會以相當普通的外觀呈現出來。默認呈現出的外觀是一個以黑色圓角作為邊框並用白色填充的矩形。想做得更好嗎?看看下面怎麼做。

修改活動在工作流視圖設計器中的外觀

工作流視圖設計器其實基於通用的Visual Studio設計器。自.NET 1.0以來,.NET Framework中就有組件幫助你把你的自定義對象集成到通用功能的設計器中。這些組件中的一個就是Designer特性,它嵌入代碼中被執行,視圖設計器使用它去控制如對象的展示和外觀之類的事情。

WF通過提供一種機制延伸了這一概念,它通過一個theme來為可視化活動的展現提供支持。主題(theme)實際上只不過是一個設計器類,它包含許多的屬性,你能設置它們以便去控制你的活動被怎樣繪制。你能控制呈現的顏色、邊框線的風格及顏色等等。

你也能控制它在視圖設計器中的行為。例如,你能把一些東西添加到使用鼠標右鍵點擊活動時所彈出的快捷菜單中。主題和行為操作兩者都要求你去寫一個派生於ActivityDesigner或CompositeActivityDesigner(針對組合活動)的類。對於我們的例子,我們將創建一個專門的命名為FtpGetFileActivityDesinger的設計器類。

添加一個可視化設計器到FtpGetFileActivity工作流活動中

1.這裡你將以和前一節同樣的方式開始我們的工作:創建一個新類。為此,向FtpActivity項目中添加一個名稱為FtpGetFileActivityDesigner.cs的類文件。

2.向該源文件中插入下面的名稱空間,把它們放到已存在的名稱空間語句的下面:

using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Workflow.Activities;
using System.Workflow.ComponentModel.Design;

3.因為你正創建的設計器類派生自ActivityDesigner,因此你需要修改源文件中的類定義。使用下面的類定義來替換Visual Studio為你自動生成的類定義:

public class FtpGetFileActivityDesigner : ActivityDesigner

備注:再重復一次,因為這是一個基本活動,因此你正創建的設計器類派生自ActivityDesigner。但是,假如這個活動是一個組合活動的話,你應該使用CompositeActivityDesigner類來作為基類。

4.ActivityDesigner提供了幾個虛擬的屬性和方法,你能重寫它們以便把行為外觀添加到視圖設計器中。例如Verbs屬性可以讓你添加上下文選擇菜單。做這些相當地簡單,從行為外觀的角度來看FTP活動不需要特別的支持,但它在調節視覺方面是很不錯的。為做這些,首先在FtpGetFileActivityDesigner類定義的前面添加下面的特性標記:

[ActivityDesignerThemeAttribute(typeof(FtpGetFileActivityDesignerTheme))]

5.你剛剛添加的特性指定了一個包含繪制屬性任務的設計器主題類,我們現在就來創建這個類。尋找FtpGetFileActivityDesigner類的結束(右邊)大括號,在該大括號的下面添加如下這個內部(internal)類:

FtpGetFileActivityDesignerTheme類
internal sealed class FtpGetFileActivityDesignerTheme :
                     ActivityDesignerTheme
{
  public FtpGetFileActivityDesignerTheme(WorkflowTheme theme)
    : base(theme)
  {
    this.BorderColor = Color.Black;
    this.BorderStyle = DashStyle.Solid;
    this.BackColorStart = Color.Silver;
    this.BackColorEnd = Color.LightBlue;
    this.BackgroundStyle = LinearGradientMode.Horizontal;
  }
}

備注:組合活動也有它們自己的設計器主題類:CompositeDesignerTheme。那是因為組合活動需要去呈現子活動,並且你可能想在視覺外觀上進行更嚴格的控制。

6.在有了驗證器和工具箱位圖後,你需要為FtpGetFileActivity類添加一個特性來通知工作流視圖設計器你有為展示你的活動所需的基於ActivityDesigner的信息。

[Designer(typeof(FtpGetFileActivityDesigner), typeof(IDesigner))]

7.編譯該項目,修正任何出現的編譯錯誤。

FtpGetFileActivityDesigner的完整文件如清單13-3所示。假如我們需要的話,我們能在設計器類上做更多的工作,但在這個例子中,該設計器類的存在僅僅只是添加主題。該活動將在工作流視圖設計器中以銀色到白藍色的顏色水平漸變並以實心邊框線的風格呈現出來。

清單13-3 FtpGetFileActivityDesigner.cs的完整源代碼

還剩下一個細節:當它加載進工具箱後,FtpGetFileActivity的名稱和圖標都將會展示出來。

FtpGetFileActivityDesigner.cs的完整源代碼

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Workflow.Activities;
using System.Workflow.ComponentModel.Design;
namespace FtpActivity
{
  [ActivityDesignerThemeAttribute(typeof(FtpGetFileActivityDesignerTheme))]
  public class FtpGetFileActivityDesigner : ActivityDesigner
  {
  }
  internal sealed class FtpGetFileActivityDesignerTheme : ActivityDesignerTheme
  {
    public FtpGetFileActivityDesignerTheme(WorkflowTheme theme)
      : base(theme)
    {
      this.BorderColor = Color.Black;
      this.BorderStyle = DashStyle.Solid;
      this.BackColorStart = Color.Silver;
      this.BackColorEnd = Color.LightBlue;
      this.BackgroundStyle = LinearGradientMode.Horizontal;
    }
  }
}

把自定義活動集成到工具箱中

如你所知,當你的活動被裝到Visual Studio工具箱中後,ToolboxBitmapAttribute會顯示一個和你的活動關聯的圖標。但碰巧的是,你能做比剛剛顯示一個位圖更多的事。

例如組合活動,通常要為其正常運行創建所必須的子活動。一個極好的例子是IfElse活動。當你拖拽一個IfElse活動到你的工作流中的時候,它會自動填充一個左右分支活動。在這裡我不會顯示怎樣做這些,因為我們正創建的是一個基本活動。但在這節的末尾我將提供一個獲取更多信息的鏈接以及創建組合活動並預先用子活動來填充它們的示例代碼。

因此,如果我們不添加子活動的話,我們還需要完成些什麼事才能把我們的活動集成到工具箱中呢?對這件事來說,如沒有其它的指示,Visual Studio將把你的活動加載進工具箱中並使用類的名字作為它顯示的名字。因為有其它的WF活動沒有使用它們的類名來作為顯示名,因此我們將對默認的行為進行重寫並提供一個更像是真正的標准WF元素的顯示名(不使用類名來作為顯示名)。盡管我們所有要調整的事情就是這些,但你也能修改像包含一個描述信息、你的公司名稱以及一個版本號在內的其它事情。

你也能提供過濾,以便讓你的活動只在基於工作流中使用時呈現,但你很快將使用的ActivityToolboxItem基類為你提供了這種行為。

為FtpGetFileActivity工作流活動添加工具箱集成

1.和前面兩節一樣,你要創建一個新類,在FtpActivity項目中添加一個名稱為FtpGetFileActivityToolboxItem.cs的類文件。

2.添加下面的名稱空間,把它們放到現存的名稱空間的下面:

using System.Workflow.ComponentModel.Design;
using System.Runtime.Serialization;
   3.你正創建的類必須從ActivityToolboxItem派生。因此,你需要修改Visual Studio為你創建的默認的類定義。用下面的內容替換該類的類定義。

class FtpGetFileActivityToolboxItem : ActivityToolboxItem

4.FtpGetFileActivityToolboxItem類必須被標記為可序列化的,因此在剛才類定義的前面添加Serializable特性。

[Serializable]

5.現在添加該類的主要部分。你需要三個構造器:一個默認的構造器,一個帶參數的構造器和一個序列化構造器。每一個構造器都將調用InitializeComponent來指定它的顯示名稱。

FtpGetFileActivityToolboxItem類的構造器
public FtpGetFileActivityToolboxItem()
{
  // Initialize
  InitializeComponent();
}
public FtpGetFileActivityToolboxItem(Type type)
  : base(type)
{
  // Initialize
  InitializeComponent();
}
private FtpGetFileActivityToolboxItem(SerializationInfo info, StreamingContext context)
{
  // Call base method to deserialize.
  Deserialize(info, context);
  // Initialize
  InitializeComponent();
}
protected void InitializeComponent()
{
  // Assign the display name
  this.DisplayName = "FTP File Get";
}

備注:有一個虛擬方法Initialize,你可以重寫它去指定要顯示的名稱。但是這個方法並不總會被調用。因此提供我們自己的InitializeComponent方法是確保指定的顯示名稱在所有情況下都有效的最好方式。

6.為確保你剛剛創建的ToolboxItem被FTP活動使用,需要把下面的特性添加到你已經為FtpGetFileActivity添加的一組特性的下面。

[ToolboxItem(typeof(FtpGetFileActivityToolboxItem))]

7.編譯FtpActivity項目,修正任何可能出現的編譯錯誤。

隨著這最後的一個步驟,你的自定義活動就完成了。但是,FileGrabber應用程序是不完整的。你需要添加一個使用FtpGetFileActivity的工作流,並為FileGrabber應用程序添加必須的代碼以便調用該工作流。我們首先創建該工作流。

添加一個工作流並使用FtpGetFileActivity工作流活動

1.右鍵點擊FileGrabber解決方案,然後選擇“添加”。從子菜單中選中“新建項目”。

2.新建的項目類型選擇“順序工作流庫”,名稱命名為“GrabberFlow”。

3.Visual Studio添加了一個新的順序工作流庫後會打開工作流視圖設計器,讓你可直接開始編輯你的工作流。打開Visual Studio工具箱後,你應該在那裡能找到FtpGetFileActivity。

備注:你或許會驚訝,漂亮的小FTP位圖到哪裡去了(取而代之的是一個藍色齒輪圖標),以及你在FtpGetFileActivityToolboxItem類中添加的顯示文本為什麼沒有在工具箱中顯示出來。這是因為FtpGetFileActivity由當前解決方案中的一個程序集支持。我將在你完成了該工作流後來描述解決這些問題的辦法。

4.拖拽一個FtpGetFileActivity到你的設計器界面上。

5.帶感歎號標記的紅點指明了當前存在一些驗證錯誤。並且事實上,假如你把鼠標放到向下的箭頭上並單擊的話,你將看到詳細的驗證失敗信息。它看起來眼熟嗎?哦...它是你在前面章節創建活動驗證類時所插入的相關驗證錯誤信息。

6.FileGrabber主應用程序要能夠把用戶名、密碼和文件的URL傳進你的工作流中。因此你需要在你的工作流中為所有這些值都提供一個屬性。這裡有一個很棒的方式來完成這些任務:讓Visual Studio為你添加它們。假如你選中FTP活動然後在屬性面板中看看它的屬性的話,你將看到你為活動添加好的三個屬性:FtpUrl、FtpUser和FtpPassword。為了讓你首先清除錯誤的條件,你需要選中FtpUrl屬性以激活浏覽(...)按鈕。點擊該浏覽按鈕。

7.這將激活“將‘FtpUrl’綁定到活動的屬性”對話框。點擊“綁定到新成員”選項卡,在“新成員名稱”中輸入“FtpUrl”,確保選中的是“創建屬性”。最後點擊“確定”。(注意現在帶感歎號標記的紅點消失了。)

8.按照相同的步驟(步驟6和步驟7)添加一個新的FtpUser屬性和一個新的FtpPassword屬性。當你完成這些後,屬性面板顯示的為所有這三個屬性的綁定效果如下圖所示:

9.編譯該工作流項目,假如存在錯誤的話,請糾正這些錯誤。

我在第三步中提到過,我會描述怎樣把FtpGetFileActivity加載進工具箱中去顯示出你在前面章節中添加的實際已存在的元數據。下面就是你要做的。

把FtpGetFileActivity工作流活動加載進工具箱中

1.對這一工作來說,你必須在工作流視圖設計器中有一個工作流。(工具箱會過濾掉不適合的組件。)GrabberFlow工作流應該被加載進工作流視圖設計器中了,如沒有的話,重新加載它並打開工具箱。在工具箱內容體(不是標題)上點擊鼠標右鍵,這將彈出上下文菜單,然後選擇“選擇項”。

2.這將打開“選擇工具箱項”對話框。單擊“活動”選項卡然後點擊“浏覽”按鈕。

3.點擊“浏覽”將打開一個常見的文件對話框。使用導航工具,浏覽並定位到你本地文件系統中已編譯的FtpActivity項目對應的目錄,通常為“\Chapter13\FileGrabber\FtpActivity\bin\Debug\”(或者為“Release\”,這取決於你所選擇的生成模式)。選中FtpActivity.dll文件,點擊“打開”。然後點擊“確定”關閉“選擇工具箱項”對話框。

4.這就把FtpGetFileActivity加載進工具箱中了,並且你應該會看到你在前面所添加的自定義圖標和顯示文本。

我們最後的任務是去添加在主應用程序中開始該工作流所需的代碼。

執行FtpGetFileActivity工作流

1.在代碼視圖模式下打開Form1.cs文件。

2.除了真正啟動工作流實例所需的代碼外,你需要的所有代碼我都已經為你添加好了。該代碼將放進Get_Click事件處理程序中。因此找到Get_Click事件處理程序,在末尾添加如下代碼:

Get_Click事件處理程序
// Process the request, starting by creating the parameters
Dictionary<string, object> parms = new Dictionary<string, object>();
parms.Add("FtpUrl", tbFtpUrl.Text);
parms.Add("FtpUser", tbUsername.Text);
parms.Add("FtpPassword", tbPassword.Text);
// Create instance.
_workflowInstance = _workflowRuntime.CreateWorkflow(typeof(GrabberFlow.Workflow1), parms);
// Start instance.
_workflowInstance.Start();

3.因為你正使用的工作流來自於GrabberFlow名稱空間,因此你需要添加對該工作流程序集的項目級引用。

4.按下F5(或者Ctrl+F5)執行FileGrabber。假如你提供了一個有效的FTP URL文件地址,該文件會被下載嗎?(注意該文件將被下載並放到和你的應用程序的可執行文件相同目錄的位置中。)

在這一章,我們創建了一個基本活動。這些必需的步驟對於創建一個組合活動來說也是相似的,只是稍微多了一些調用。(例如,你創建的ToolBoxItem就多些額外的代碼去方便對所容納的活動進行添加。)假如你想閱讀關於組合活動創建的更多資料的話,你可以在http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnlong/html/parallelif.asp中找到

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved