<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Go with the Flow</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/cnflow/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/cnflow/feed.xml</link>
    <description />
    <lastBuildDate>Wed, 17 Apr 2019 03:19:04 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Workflow Designer总是hang？推荐一个WPF的hotfix！</title>
      <link>https://docs.microsoft.com/archive/blogs/cnflow/workflow-designerhangwpfhotfix</link>
      <pubDate>Tue, 09 Aug 2011 19:40:00 GMT</pubDate>
      <dc:creator><![CDATA[Guang Yang - MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/cnflow/2011/08/09/workflow-designerhangwpfhotfix/</guid>
      <description><![CDATA[最近我们听到一些用户反应在某些情况下（而且还不是非常复杂的工作流），WF4工作流设计器会突然变慢甚至hang在那里。收到这些反馈之后，我们积极的与这些用户合作，最后发现他们碰到的问题其实是由一个WPF...]]></description>
      <content:encoded><![CDATA[<p>最近我们听到一些用户反应在某些情况下（而且还不是非常复杂的工作流），WF4工作流设计器会突然变慢甚至hang在那里。收到这些反馈之后，我们积极的与这些用户合作，最后发现他们碰到的问题其实是由一个WPF的bug引起的。</p>
<p>好消息是，WPF团队已经修正了这个bug并且发布了一个hotfix。所以，如果你也面临类似的问题，我建议你去安装一下这个hotfix然后再试试看。虽然不敢保证它能解决你的问题（因为造成问题的原因可能不尽相同），不过我觉得也很值得一试。</p>
<p>你可以使用如下任意一个连接下载这个hotfix。</p>
<p><a title="https://archive.msdn.microsoft.com/KB2484841" href="https://archive.msdn.microsoft.com/KB2484841">https://archive.msdn.microsoft.com/KB2484841</a><br /><br /><a title="https://connect.microsoft.com/VisualStudio/Downloads/DownloadDetails.aspx?DownloadID=35604" href="https://connect.microsoft.com/VisualStudio/Downloads/DownloadDetails.aspx?DownloadID=35604">https://connect.microsoft.com/VisualStudio/Downloads/DownloadDetails.aspx?DownloadID=35604</a><br /><br />同时，我也强烈建议安装下面这个.NET更新。因为它包含了额外一些WPF和WF 4.0的bug fix。<br /><br /><a title="https://www.microsoft.com/download/en/details.aspx?id=3556" href="https://www.microsoft.com/download/en/details.aspx?id=3556">https://www.microsoft.com/download/en/details.aspx?id=3556</a><br /><br />赶快去安装试试看吧！</p>]]></content:encoded>
    </item>
    <item>
      <title>[How To] 如何编程实现保存WF 4工作流定义到图片</title>
      <link>https://docs.microsoft.com/archive/blogs/cnflow/how-to-wf-4</link>
      <pubDate>Sun, 12 Dec 2010 02:44:00 GMT</pubDate>
      <dc:creator><![CDATA[Guang Yang - MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/cnflow/2010/12/12/how-to-wf-4/</guid>
      <description><![CDATA[使用WF...]]></description>
      <content:encoded><![CDATA[<p>使用WF 4创建工作流的一大好处是图形化的设计器。也就是说在大多数情况下，开发人员不需要通过写代码的方式定义工作流，而是使用我们提供的设计器以图形化的方式创建出来。这不但大大提高了开发人员的生产力，更降低了设计流程的门槛以便非开发人员使用。图形化的另一个好处是直观、容易理解，因此在它几乎被所有工作流系统中。</p>
<p>举例来说，很多工作流系统中都有如下所述的典型应用场景：</p>
<ol>
<li>业务人员使用工作定义一套业务流程，当然是以图形化的方式<img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/32/28/metablogapi/3113.wlEmoticon-winkingsmile_1A220E5C.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-01-32-28-metablogapi/3113.wlEmoticon_2D00_winkingsmile_5F00_1A220E5C.png" alt="Winking smile" class="wlEmoticon wlEmoticon-winkingsmile" style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" /> </li>
<li>在使用这套业务流程的过程中，用户需要在系统的界面上（可能是桌面程序或网页）看到这个工作流的定义图，以便理解流程的逻辑。 </li>
</ol>
<p>为了实现这一应用场景，一个比较典型的做法是把工作流定义图保存成图片并显示给最终用户。最近在看MSDN WF 4论坛的时候，发现有一些开发人员不知道如何编程把WF 4工作流定义保存到图片，而有些客户也通过邮件向我提出同样的问题。今天我就来跟大家分享一下如何实现这个功能。</p>
<p>什么？难道WF 4默认不提供这一功能吗？还需要我自己写代码？有些朋友（特别是使用过WF 3.x的人）可能会发出这样的疑问。的确，WF 3.x中有一个很方便的API供你使用，而在WF 4中没有。主要原因是WF 3.x在图形方面使用的是WinForm而WF 4使用的WPF。WinForm支持在界面控件还没有被创建出来的时候生成图片，因此我们可以提供一个API来保存流程图。但是WPF却不支持这一点，也就是说，在WF 4中，你一定要先打开设计器（Workflow Designer），然后才能保存图片。正是由于这个约束，我们才无法实现保存图片的API。不过好在自己实现这一功能也比较简单，只不过有一些tricky的地方需要注意。我保证读完这篇文章，你就会觉得是小菜一碟儿了。</p>
<h1>基本想法</h1>
<p>实现保存图片功能的基本想法很简单：</p>
<ol>
<li>新建一个工作流设计器（Workflow Designer） </li>
<li>打开需要保存图片的工作流定义 </li>
<li>保存图片 </li>
<li>关闭工作流设计器 </li>
</ol>
<p>其中第一、二步是必要的，因为就像我之前提到的WPF要求在创建出界面控件之后才能保存图片<img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/32/28/metablogapi/1663.wlEmoticon-sadsmile_26438883.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-01-32-28-metablogapi/1663.wlEmoticon_2D00_sadsmile_5F00_26438883.png" alt="Sad smile" class="wlEmoticon wlEmoticon-sadsmile" style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" />。当然我们不需要打开Visual Studio，还记得WF 4提供一个rehostable workflow designer吗？对，我们就用它。关于如何创建一个rehostable workflow designer，请参考我们在MSDN上提供的<a href="https://msdn.microsoft.com/en-us/library/dd699776.aspx">示例代码</a>。你也可以在<a href="https://www.microsoft.com/downloads/en/details.aspx?FamilyID=35ec8682-d5fd-4bc3-a51a-d8ad115a8792&amp;displaylang=en">这里</a>下载到整套的WF 4示例。</p>
<h1>写代码试试看</h1>
<p>那么让我们写代码试试看。先来看看rehostable workflow designer的基本代码</p>
<pre class="code"><span style="color: blue">namespace </span>Microsoft.Samples.DesignerRehosting
{
    <span style="color: blue">public partial class </span><span style="color: #2b91af">RehostingWfDesigner </span>: <span style="color: #2b91af">Window
    </span>{
        <span style="color: blue">private </span><span style="color: #2b91af">WorkflowDesigner </span>workflowDesigner;

<span style="color: blue">        public </span>RehostingWfDesigner()
        {
            InitializeComponent();
        }

        <span style="color: blue">protected override void </span>OnInitialized(<span style="color: #2b91af">EventArgs </span>e)
        {
            <span style="color: blue">base</span>.OnInitialized(e);

            <span style="color: green">// register metadata
            </span>(<span style="color: blue">new </span><span style="color: #2b91af">DesignerMetadata</span>()).Register();
            <span style="color: green">// create a big workflow for saving image</span>
            <span style="color: #2b91af">Activity </span>workflow = <span style="color: blue">new </span><span style="color: #2b91af">Sequence
            </span>{
                Activities = { 
                    <span style="color: blue">new </span><span style="color: #2b91af">Sequence</span>(), <span style="color: blue">new </span><span style="color: #2b91af">Sequence</span>(), <span style="color: blue">new </span><span style="color: #2b91af">Sequence</span>(),
                    <span style="color: blue">new </span><span style="color: #2b91af">Sequence</span>(), <span style="color: blue">new </span><span style="color: #2b91af">Sequence</span>(), <span style="color: blue">new </span><span style="color: #2b91af">Sequence</span>(),
                    <span style="color: blue">new </span><span style="color: #2b91af">Sequence</span>(), <span style="color: blue">new </span><span style="color: #2b91af">Sequence</span>(), <span style="color: blue">new </span><span style="color: #2b91af">Sequence</span>()
                }
            };
            <span style="color: green">// create the workflow designer and load the workflow
            </span>workflowDesigner = <span style="color: blue">new </span><span style="color: #2b91af">WorkflowDesigner</span>();
            workflowDesigner.Load(workflow);
            DesignerBorder.Child = workflowDesigner.View;
        }
    }
}</pre>
<p>接着我们来看看如何在WPF中为界面控件生成一张图片：</p>
<pre class="code"><span style="color: #2b91af">BitmapFrame </span>CreateWorkflowDefinitionImage()
{
    <span style="color: blue">const double </span>DPI = 96.0;
    <span style="color: green">// this is the designer area we want to save
    </span><span style="color: #2b91af">Visual </span>areaToSave = ((<span style="color: #2b91af">DesignerView</span>)<span style="color: #2b91af">VisualTreeHelper</span>.GetChild(
<span style="color: blue">        this</span>.workflowDesigner.View, 0)).RootDesigner;
    <span style="color: green">// get the size of the targeting area
    </span><span style="color: #2b91af">Rect </span>size = <span style="color: #2b91af">VisualTreeHelper</span>.GetDescendantBounds(areaToSave);
    <span style="color: #2b91af">RenderTargetBitmap </span>bitmap = <span style="color: blue">new </span><span style="color: #2b91af">RenderTargetBitmap</span>((<span style="color: blue">int</span>)size.Width, (<span style="color: blue">int</span>)size.Height,
        DPI, DPI, <span style="color: #2b91af">PixelFormats</span>.Pbgra32);
    bitmap.Render(areaToSave);
    <span style="color: blue">return </span><span style="color: #2b91af">BitmapFrame</span>.Create(bitmap);
}</pre>
<p>这段代码比较直观，就是得到workflow designer中工作流图形的部分，然后使用WPF的一些API在内存中创建一张图片。接下来如果需要保存的一个文件的话，就比较简单了：</p>
<pre class="code"><span style="color: blue">void </span>SaveImageToFile(<span style="color: blue">string </span>fileName, <span style="color: #2b91af">BitmapFrame </span>image)
{
    <span style="color: blue">using </span>(<span style="color: #2b91af">FileStream </span>fs = <span style="color: blue">new </span><span style="color: #2b91af">FileStream</span>(fileName, <span style="color: #2b91af">FileMode</span>.Create))
    {
        <span style="color: #2b91af">BitmapEncoder </span>encoder = <span style="color: blue">new </span><span style="color: #2b91af">JpegBitmapEncoder</span>();
        encoder.Frames.Add(<span style="color: #2b91af">BitmapFrame</span>.Create(image));
        encoder.Save(fs);
        fs.Close();
    }
}</pre>
<p>最后我们尝试在<span style="font-family: 'Courier New';"><span style="color: blue">protected override void </span>OnInitialized(<span style="color: #2b91af">EventArgs </span>e)</span>的最后调用以上两个函数保存图片：</p>
<pre class="code"><span style="color: blue">protected override void </span>OnInitialized(<span style="color: #2b91af">EventArgs </span>e)
{
    ...
<span style="color: blue"><span style="color: #000000;">    </span>this</span>.SaveImageToFile(<span style="color: #a31515">"test.jpg"</span>, <span style="color: blue">this</span>.CreateWorkflowDefinitionImage());
<pre class="code"><span style="color: #2b91af">    Application</span>.Current.Shutdown();
</pre>
}</pre>
<h1>怎么会抛异常？</h1>
<p>好，我们来运行以上代码！等等，为什么会有抛异常？</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/32/28/metablogapi/5367.exception_18B27E8C.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-01-32-28-metablogapi/5367.exception_5F00_18B27E8C.png"><img height="147" width="240" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/32/28/metablogapi/3286.exception_thumb_0FDE6241.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-01-32-28-metablogapi/3286.exception_5F00_thumb_5F00_0FDE6241.png" alt="exception" border="0" title="exception" style="background-image: none; border-right-width: 0px; margin: ; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" /></a></p>
<p>稍微debug一下不难发现，原因是我们想要保存图片的区域的大小是负数。这是为什么呢？原来虽然我们是在打开workflow designer之后才保存的图片，但是在保存图片是，相应的界面控件并没有创建完毕，因此才得到了负数。这个问题要怎么解决呢？WPF中的每个控件都有一个LayoutUpdated事件，意思是控件已经创建并布局好了。然而仅仅简单的监听这个事件还不够，因为在完全创建好工作流定义图之前，控件会被布局很多次。因此，我们还要用一个计时器（Timer）：</p>
<pre class="code"><span style="color: blue">private </span>System.Timers.<span style="color: #2b91af">Timer </span>timer;
<span style="color: blue">private delegate void </span><span style="color: #2b91af">TimerDelegate</span>();

<span style="color: blue">protected override void </span>OnInitialized(<span style="color: #2b91af">EventArgs </span>e)
{
    <span style="color: blue">this</span>.timer = <span style="color: blue">new </span>System.Timers.<span style="color: #2b91af">Timer</span>(1000);
    <span style="color: blue">this</span>.timer.AutoReset = <span style="color: blue">false</span>;
    <span style="color: blue">this</span>.timer.Elapsed += <span style="color: blue">new </span><span style="color: #2b91af">ElapsedEventHandler</span>(CaptureTimer_Elapsed);
    <span style="color: blue">this</span>.timer.Start();
    workflowDesigner.View.LayoutUpdated += <span style="color: blue">new </span><span style="color: #2b91af">EventHandler</span>(View_LayoutUpdated);
}

<span style="color: blue">void </span>CaptureTimer_Elapsed(<span style="color: blue">object </span>sender, <span style="color: #2b91af">ElapsedEventArgs </span>e)
{
    <span style="color: blue">this</span>.timer.Stop();
    <span style="color: blue">this</span>.timer = <span style="color: blue">null</span>;
    <span style="color: blue">this</span>.workflowDesigner.View.Dispatcher.BeginInvoke(
        System.Windows.Threading.<span style="color: #2b91af">DispatcherPriority</span>.ApplicationIdle,
        (<span style="color: #2b91af">TimerDelegate</span>)<span style="color: blue">delegate</span>()
        {
            <span style="color: blue">this</span>.SaveImageToFile(<span style="color: #a31515">"test.jpg"</span>, <span style="color: blue">this</span>.CreateWorkflowDefinitionImage());
            <span style="color: #2b91af">Application</span>.Current.Shutdown();
        });
}

<span style="color: blue">void </span>View_LayoutUpdated(<span style="color: blue">object </span>sender, <span style="color: #2b91af">EventArgs </span>e)
{
<span style="color: blue">    if </span>(<span style="color: blue">this</span>.timer != <span style="color: blue">null</span>)
    {
        <span style="color: blue">this</span>.timer.Stop();
        <span style="color: blue">this</span>.timer.Start();
    }
}</pre>
<h1>怎么保存不全？</h1>
<p>好，我们再来运行试试。好！没有异常了！快去\bin\Debug下面看看保存的图片！哎？怎么有几个活动设计器不对呢？没有具体的活动设计器，只有个框而已。（为了节省版面，这里我把图片旋转了一下，实际上是垂直的没错，只是最后两个Sequence保存的有问题）</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/32/28/metablogapi/8345.test_6E8ACE72.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-01-32-28-metablogapi/8345.test_5F00_6E8ACE72.jpg"><img height="45" width="240" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/32/28/metablogapi/2844.test_thumb_5A04BD4D.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-01-32-28-metablogapi/2844.test_5F00_thumb_5F00_5A04BD4D.jpg" alt="test" border="0" title="test" style="background-image: none; border-right-width: 0px; margin: ; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" /></a></p>
<p>想要知道产生这个现象的原因，我们就需要讨论一下workflow designer中的一个高级机制叫做<strong>虚拟化（Virtualization）</strong>。在这里，虚拟化的作用是：如果某些活动还没有出现在workflow designer中的可视区域内，我们就不去创建相关的活动设计器。这样做主要是为了提高workflow designer的性能。想象一下你的工作流中有上百个活动，但是在你的屏幕中一次只能看到其中十个。如果没有虚拟化，我们就不得不把所有上百个活动的设计器创建出来，这就会大大降低整个设计器的性能。而这里有问题的两个Sequence恰恰是被虚拟化的、还有没被创建出设计器的活动。</p>
<p>好了，原因说清楚了。那么怎么解决呢？道理是明摆着的，就是要让所有活动都出现在可视区域内。不过要怎么做呢？别急，我们的workflow designer提供了一个Fit to Screen功能，就是把整个工作流定义的图形缩放到在可视区域内完全显示。我们可以利用这一功能显示所有的活动。相应的代码加在哪里呢？对，<span style="font-family: 'Courier New';"><span style="color: blue">void </span>View_LayoutUpdated(<span style="color: blue">object </span>sender, <span style="color: #2b91af">EventArgs </span>e) </span></p>
<pre class="code"><span style="color: blue">private bool </span>IsVirtualized = <span style="color: blue">false</span>;

<span style="color: blue">void </span>View_LayoutUpdated(<span style="color: blue">object </span>sender, <span style="color: #2b91af">EventArgs </span>e)
{
    <span style="color: blue">if </span>(!IsVirtualized)
    {
        ((<span style="color: #2b91af">RoutedCommand</span>)<span style="color: #2b91af">DesignerView</span>.FitToScreenCommand).Execute(<span style="color: blue">null</span>,
            <span style="color: blue">this</span>.workflowDesigner.Context.Services.GetService&lt;<span style="color: #2b91af">DesignerView</span>&gt;());
        IsVirtualized = <span style="color: blue">true</span>;
    }
    <span style="color: blue">if </span>(<span style="color: blue">this</span>.timer != <span style="color: blue">null</span>)
    {
        <span style="color: blue">this</span>.timer.Stop();
        <span style="color: blue">this</span>.timer.Start();
    }
}</pre>
<h1>搞定！</h1>
<p>最后我们再来运行一下。OK，这回图片正确啦！（同样，为了节省版面，这里我把图片旋转了一下）</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/32/28/metablogapi/5153.test_final_03CC2211.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-01-32-28-metablogapi/5153.test_5F00_final_5F00_03CC2211.jpg"><img height="40" width="240" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/32/28/metablogapi/1856.test_final_thumb_4AD17CA9.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-01-32-28-metablogapi/1856.test_5F00_final_5F00_thumb_5F00_4AD17CA9.jpg" alt="test_final" border="0" title="test_final" style="background-image: none; border-bottom: 0px; border-left: 0px; margin: ; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" /></a></p>
<p>最终版的代码可以在<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/32/28/code/8372.SaveImage.zip" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-01-32-28-code/8372.SaveImage.zip">这里</a>下载。希望以上讲解和示例能够给给我带来一些帮助。</p>]]></content:encoded>
    </item>
    <item>
      <title>Tech.Ed 2010北京归来</title>
      <link>https://docs.microsoft.com/archive/blogs/cnflow/tech-ed-2010</link>
      <pubDate>Wed, 08 Dec 2010 01:41:00 GMT</pubDate>
      <dc:creator><![CDATA[Guang Yang - MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/cnflow/2010/12/08/tech-ed-2010/</guid>
      <description><![CDATA[从今年的Tech.Ed北京回来已经好几天了。由于11月30号就动身而12月4号才回到上海，落下了很多日常工作，所以一回来就赶紧补课，一直没有时间总结一下今年的Tech.Ed与大家分享。现在总算是有时间...]]></description>
      <content:encoded><![CDATA[<p>从今年的<a href="https://technet.microsoft.com/zh-cn/ff934861.aspx">Tech.Ed北京</a>回来已经好几天了。由于11月30号就动身而12月4号才回到上海，落下了很多日常工作，所以一回来就赶紧补课，一直没有时间总结一下今年的Tech.Ed与大家分享。现在总算是有时间喘口气了，赶紧利用一下跟各位讲讲这次Tech.Ed有趣的事情。</p>
<h1>主题</h1>
<p>今年Tech.Ed北京的主题毫无疑问是<a href="https://www.microsoft.com/en-us/cloud/default.aspx">云计算</a>（Windows Azure）和<a href="https://www.microsoft.com/windowsphone/en-us/default.aspx">Windows Phone 7</a>，这一点但凡是关注一点儿业界新闻的同志们都不会觉得奇怪。云计算依然是IT领域的未来发展趋势，而我个人认为，Microsoft毫无疑问是这一领域投入最多、技术最成熟、推广力度最大的公司。Windows Phone 7是在11月份刚刚发布的新东西，目前市场业绩非常不错，是Microsoft在消费品及移动终端领域的重要战略。这也难怪这次大会会这两个重量级的家伙为主题。更重要的是，Microsoft一直以来都在强调云+端的威力，而Windows Azure + Windows Phone 7恰恰是展现这一策略的最佳组合。</p>
<p>所以我们看到，在Simon老大跟Enwei老大的主题演讲中，Windows Azure与Windows Phone 7占了很大的比重。而在随后由4个总经理level的老大分别给出的4门基础课程中，Windows Azure跟Windows Phone 7也当仁不让的拿下了3席。</p>
<p>这意味着什么？很显然Windows Azure和Windows Phone 7将成为明年的绝对潮流。还没开始跟进吗？当心落伍哦~</p>
<h1>课程</h1>
<p>有了以上两个主题，我们作为产品团队，当然也要向之靠拢。今年我们的参与阵容可谓庞大，浩浩荡荡10余人。一共开展了3项课程，4个动手实验室，同时还有一个展台。下面帮大家回顾一下课程的大致内容。没有参加Tech.Ed的同志们要注意了，这里有课程讲义下哦！</p>
<p><a href="https://www.teched.com.cn/2010/customer/y/SessionView_pop.asp?SessionID=DEV-LANG-300-4"><strong>课程一：使用WCF开发REST服务 ── 在Windows Server AppFabric 上，在云端</strong></a></p>
<ul>
<li>简单介绍REST以及其与HTTP的关系 </li>
<li>如何使用WCF创建REST服务 </li>
<li>WCF 4中对REST服务支持的增强，包括简化的配置、更好的缓存、更灵活的格式选择等 </li>
<li>隆重推出<a href="https://wcf.codeplex.com">https://wcf.codeplex.com</a> </li>
<li>对下一代WCF的展望 </li>
</ul>
<div class="wlWriterEditableSmartContent" id="scid:fb3a1972-4489-4e52-abe7-25a00bb07fdf:c4cbb94c-c676-4027-b879-f8bababf7e5a" style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px">
<p><a title="课程讲义下载" href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/32/28/deck/7774.DEV-LANG-300-4_9B854F654F658765CC51.pptx" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-01-32-28-deck/7774.DEV_2D00_LANG_2D00_300_2D00_4_5F009B854F654F658765CC51_.pptx">课程讲义下载</a></p>
</div>
<p><a href="https://www.teched.com.cn/2010/customer/y/SessionView_pop.asp?SessionID=DEV-LANG-300-2"><strong>使用WF 4实现您的流程 ── 在Windows Server AppFabric上，在云端</strong></a></p>
<ul>
<li>简单介绍什么是<a href="https://msdn.microsoft.com/en-us/netframework/aa663328.aspx">WF 4</a>，三个关键字：活动（Activity）、运行时（Runtime）、工具（Tooling） </li>
<li>WF 4适用于哪些典型的应用场景：长时间运行的任务、流程的二次定制，以及协调复杂的业务逻辑 </li>
<li>以一个典型的审批流程详细的演示了： 
    
<ul>
<li>如何创建简单的活动、如何创建一个工作流服务、如何在WF 4中访问数据库，以及如何把WF 4整合到ASP.NET中 </li>
<li>如何实现复杂的业务逻辑，例如审批的驳回以及会签 </li>
<li>如何部署并管理工作流实例到<a href="https://msdn.microsoft.com/en-us/windowsserver/ee695849.aspx">Windows Server AppFabric</a>和<a href="https://www.microsoft.com/windowsazure/windowsazure/">Windows Azure</a>上 </li>
</ul>
</li>
<li>下一代WF会有哪些激动人心的新特性 </li>
</ul>
<div class="wlWriterEditableSmartContent" id="scid:fb3a1972-4489-4e52-abe7-25a00bb07fdf:a0f049da-878d-4e66-a8a0-892f76f9641c" style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px">
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/32/28/deck/7360.DEV-LANG-300-2_686749516A6C8F5B.pptx" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-01-32-28-deck/7360.DEV_2D00_LANG_2D00_300_2D00_2_5F00686749516A6C8F5B_.pptx" title="课程讲义下载">课程讲义下载</a></p>
</div>
<p><a href="https://www.teched.com.cn/2010/customer/y/SessionView_pop.asp?SessionID=DEV-LANG-300-5"><strong>下一代中间件平台AppFabric纵览</strong></a></p>
<ul>
<li>AppFabric的总体架构，包括<a href="https://msdn.microsoft.com/en-us/windowsserver/ee695849.aspx">Windows Server AppFabric</a>和<a href="https://www.microsoft.com/en-us/appfabric/azure/default.aspx">Windows Azure AppFabric</a> </li>
<li>演示如何在Windows Server AppFabric中部署、配置、监测WCF/WF服务并管理工作流实例 </li>
<li>展望未来，下一代AppFabric特别是在云端的特性以及AppFabric云端管理平台的演示 </li>
</ul>
<div class="wlWriterEditableSmartContent" id="scid:fb3a1972-4489-4e52-abe7-25a00bb07fdf:8f31c683-512c-4190-9832-9abc5d2d2da7" style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px">
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/32/28/deck/4331.DEV-LANG-300-5_18526867915C696DD47F.pptx" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-01-32-28-deck/4331.DEV_2D00_LANG_2D00_300_2D00_5_5F0018526867915C696DD47F_.pptx">课程讲义下载</a></p>
</div>
<h1>Channel 9</h1>
<p>严肃的内容就到这里，Tech.Ed也有轻松有趣的一面。这一次我很幸运接受了Channel 9中文频道的采访，跟Tech.Ed的现场观众以及网络上的朋友分享WF的一些知识以及最新动态。各位可以在这里找到我的采访视频：<a href="https://topic.it168.com/game/slvideo/list.aspx?id=61">WF的场景和未来特性</a>。</p>
<p>说到这次采访，就不得不提<a href="https://channel9.msdn.com/">Channel 9</a>了。Channel 9是Microsoft MSDN上的一个主要面向广大技术爱好者的视频频道，其英文网站上包含了非常多的高质量视频帮助你了解Microsoft的产品和技术。最酷的是连像<a href="https://en.wikipedia.org/wiki/Mark_Russinovich">Mark Russinovich</a>这样的大牛（Microsoft的Technical Fellow之一）都会在上面有视频分享。那针对WCF、WF和AppFabric，我们也在Channel 9的英文网站上面有<a href="https://channel9.msdn.com/Shows/Endpoint">endpoint.tv</a>这样一个连载，到目前为止已经有133集啦！我在Redmond总部出差的时候还做过一期，在这里<a href="https://channel9.msdn.com/Shows/Endpoint/endpointtv-WF-State-Machine-and-ADONET-Activity-Packs">endpoint.tv &ndash; WF State Machine and ADO.NET Activity Packs</a>.</p>
<p>这次Tech.Ed的采访是Channel 9中文频道，所以对国内的朋友也更加友好一些。虽然这个中文频道发展时间不长，但是势头很猛，相信在不久的将来可以有更多机会利用这个平台跟各位交流。顺便提一下，我还顺了间Channel 9的衣服和一个公仔，非常可爱！</p>
<p><img border="0" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/32/28/8037.channel-9-logo.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-01-32-28/8037.channel_2D00_9_2D00_logo.png" /></p>
<h1>其他及照片</h1>
<p>这次Tech.Ed期间，北京出奇的暖和。我们在会场上见到了很多熟悉的身影，有的是Microsoft的MVP，有的是之前就有过交流的朋友，有的是正在使用WF的客户。能再次见到大家真是非常的开心。值得一提的是，这一次神州数码作为使用WF 4的合作伙伴，还跟我们一起做了一堂课程，跟大家分享他们是如何在实际项目中使用WF 4。当时500多人的会场座无虚席，场面非常火爆。最后不多说了，以照片结束这篇博文，同时期待下次Tech.Ed盛会的到来！</p>
<p><img style="max-width: 550px;" border="0" src="https://public.blu.livefilestore.com/y1pHUdlIdFmeBgnolU_j0GKxO2DGLpuTylbAPE7soUTQ96-4L9mlQoz5xFq9mrUXY-KfDhKLTJ-RW9hHdDnyQiY5Q/DSC_2282.jpg?psid=1" /></p>
<p><img style="max-width: 550px;" border="0" src="https://public.blu.livefilestore.com/y1pvB7uJ1iqUudIpionrvkM-pq6tqXmK4aw4MytuSLfx5KDIMXqueY9EKqzqq9gdwJ---raX6H9z98-b-VNt8fSEA/IMG_5067.jpg?psid=1" /></p>
<p><img style="max-width: 550px;" border="0" src="https://public.blu.livefilestore.com/y1pY9Cog2tM9xFQ7uw53AzJ5skM5_M6ttrhTVtYjkKIhYdzk-tPVhoCm4KqxsoOzaf4vBPvcs-8O-fXMNB65YRRxw/IMG_5057.jpg?psid=1" /></p>
<p><img style="max-width: 550px;" border="0" src="https://public.blu.livefilestore.com/y1pONwcsNCtIE3L3PXb0-CAGaE-RaaapmKKvycXDepdYfJBOuS1dVSLkplV4ity8Z1dPI4oVvYzpscojI3x43Jg_w/IMG_5059.jpg?psid=1" /></p>
<p><img style="max-width: 550px;" border="0" src="https://public.blu.livefilestore.com/y1pXU_qv3mCQvsNTmjRepyEH5DlN8td86nDuHm_pd197OrQWDHuKt1gUC8ou9YUEyTX0vEKAV2O8VCCIR8W0zraJw/DSC_2305.jpg?psid=1" /></p>
<p><img style="max-width: 550px;" border="0" src="https://public.blu.livefilestore.com/y1pTkIoElmW-FKfnIcflZJya19oE1_DC3ZWgkG_6HZ-S34Cglug5s1qkVE4A9xQHa-Q45ImaMc3pb0zB_MVzk7-rw/DSC_2309.jpg?psid=1" /></p>
<p><img style="max-width: 550px;" border="0" src="https://public.blu.livefilestore.com/y1p3cO-x7mxlaGAIac0ebf_6rCR-UAd1iY8ftSuojxBsQ8W0PXiEvUykC-iYsV0vqtlCB5K4qpAvAE0Ol-OmB1YgQ/DSC_2355.jpg?psid=1" /></p>]]></content:encoded>
    </item>
    <item>
      <title>WF ADO.NET Activity Pack CTP1 发布啦</title>
      <link>https://docs.microsoft.com/archive/blogs/cnflow/wf-ado-net-activity-pack-ctp1</link>
      <pubDate>Wed, 21 Apr 2010 03:12:33 GMT</pubDate>
      <dc:creator><![CDATA[Guang Yang - MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/cnflow/2010/04/21/wf-ado-net-activity-pack-ctp1/</guid>
      <description><![CDATA[在上一篇博文中我向大家宣布了WF State Machine Activity Pack CTP1发布的消息。在这里，我要再告诉大家一件好事情，与State...]]></description>
      <content:encoded><![CDATA[<p>在上一篇博文中我向大家宣布了<a href="https://blogs.msdn.com/cnflow/archive/2010/04/21/wf-state-machine-activity-pack-ctp1.aspx">WF State Machine Activity Pack CTP1</a>发布的消息。在这里，我要再告诉大家一件好事情，与State Machine一起，我们还在Codeplex上发布了<a href="https://wf.codeplex.com/releases/view/43585">WF ADO.NET Activity Pack CTP1</a>。</p>  <p>这一Activity Pack包含一系列的基于<a href="https://msdn.microsoft.com/en-us/library/s7ee2dwt(VS.71).aspx">ADO.NET Data Providers</a>的WF 4活动。这些活动可以帮助你非常容易地在工作流中使用SQL语句或存储过程（stored procedure）访问数据库。下载并安装这一<a href="https://wf.codeplex.com/releases/view/43585#DownloadId=116931">Activity Pack</a>后，你就可以轻松地通过设计器或自行编码把其中提供的ADO.NET活动加到你的工作流中了。</p>  <p>除了安装文件外，我们还提供了<a href="https://wf.codeplex.com/releases/view/43585#DownloadId=117206">用户手册</a>帮助你快速了解这一Activity Pack中所包含活动的特性及使用方法。你还可以下载响应的<a href="https://wf.codeplex.com/releases/view/43585#DownloadId=117208">源代码</a>来研究研究，其中包括从活动到设计器的所有代码哦！</p>  <p>同样，你的反馈对我们至关重要。我们希望能够了了解更多你如何在工作流中访问数据库的信息。这一我们才会在将来实现提供更多更强大的数据访问功能。请一定要让我们听见你的声音！</p>]]></content:encoded>
    </item>
    <item>
      <title>WF State Machine Activity Pack CTP1 发布啦</title>
      <link>https://docs.microsoft.com/archive/blogs/cnflow/wf-state-machine-activity-pack-ctp1</link>
      <pubDate>Wed, 21 Apr 2010 02:56:36 GMT</pubDate>
      <dc:creator><![CDATA[Guang Yang - MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/cnflow/2010/04/21/wf-state-machine-activity-pack-ctp1/</guid>
      <description><![CDATA[在去年的PDC上面，我有幸主持了一个关于WF 4中State Machine的实战论坛并承诺我们会在Visual Studio 2010发布之后随即发布一个基于WF 4的State...]]></description>
      <content:encoded><![CDATA[<p>在去年的PDC上面，我有幸主持了一个关于WF 4中State Machine的<a href="https://blogs.msdn.com/cnflow/archive/2009/12/09/pdc2009-state-machine.aspx">实战论坛</a>并承诺我们会在<a href="https://www.microsoft.com/visualstudio">Visual Studio 2010</a>发布之后随即发布一个基于WF 4的State Machine的预览版本。今天，我非常高兴地告诉大家，<a href="https://wf.codeplex.com/releases/view/43586">WF State Machine Activity Pack CTP1</a>如期而至！赶快到<a href="https://wf.codeplex.com/">Codeplex</a>上下载来玩一玩吧！</p>  <p>这个预览版本包含了一个完整的State Machine运行时和图形化设计器。你将会感受到，我们对事件驱动的场景做了很大的优化。最明显的感觉是，我们简化了State Machine的运行时模型并提供了很棒的工具支持。相比WF 3中的State Machine而言，创建State及Transition变得额外简单，只需要简单拖放及连线即可。</p>  <p>一直期待State Machine在WF 4中出现的朋友们，赶快去下载并安装这个<a href="https://wf.codeplex.com/releases/view/43586#DownloadId=116930">Activity Pack</a>吧！如果你想要快速了解State Machine的功能及如何使用它，绝对不能错过我们专门编写的<a href="https://wf.codeplex.com/releases/view/43586#DownloadId=117204">用户手册</a>。如果你用过WF 3及其中的State Machine并想知道它们有什么不同，没问题，用户手册中有非常详细的对比。这还不是全部，如果你对我们是如何实现这一State Machine感兴趣的话，我们还提供从运行时到设计器的所有<a href="https://wf.codeplex.com/releases/view/43586#DownloadId=117205">源代码</a>！而且，你还将会看到越来越多的文章介绍如何使用State Machine中的各种特性以及我们设计并实现State Machine背后的故事。</p>  <p><strong>最后请切记，你的反馈对我们至关重要！</strong>我们希望能够了解更多关于你如何使用State Machine的信息，这样我们才会在未来实现一个能够满足你需求的State Machine。你的任何关于State Machine的想法都会非常有价值，例如你希望State Machine有什么功能，你觉得目前的实现有什么问题或缺陷，你希望设计器的用户体验有什么改进，等等等等。请一定要让我们听见你的声音！</p>  <p>PS。我们还同时发布了<a href="https://blogs.msdn.com/cnflow/archive/2010/04/21/wf-ado-net-activity-pack-ctp1.aspx">WF ADO.NET Activity Pack CTP1</a>哦！</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/flow/WindowsLiveWriter/WFStateMachineActivityPackCTP1Released_A3DB/state%20machine_2.jpg" original-url="https://blogs.msdn.com/blogfiles/flow/WindowsLiveWriter/WFStateMachineActivityPackCTP1Released_A3DB/state%20machine_2.jpg"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="state%20machine_2[1]" border="0" alt="state%20machine_2[1]" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/flow/WindowsLiveWriter/WFStateMachineActivityPackCTP1Released_A3DB/state%20machine_2.jpg" original-url="https://blogs.msdn.com/blogfiles/flow/WindowsLiveWriter/WFStateMachineActivityPackCTP1Released_A3DB/state%20machine_2.jpg" width="644" height="404" /></a></p>]]></content:encoded>
    </item>
    <item>
      <title>工作流内部工作原理（三）</title>
      <link>https://docs.microsoft.com/archive/blogs/cnflow/83</link>
      <pubDate>Thu, 15 Apr 2010 19:22:00 GMT</pubDate>
      <dc:creator><![CDATA[andrewau]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/cnflow/2010/04/15/83/</guid>
      <description><![CDATA[Workflow Foundation Internals (III) Andrew Au...]]></description>
      <content:encoded><![CDATA[<P>Workflow Foundation Internals (III) <BR>Andrew Au </P>
<P>接续上一篇,我们会允许有多个Activity同时被Schedule,换句话说,就是某程度上的并行处理。这情况其实很普遍，比如说多人需要审批一份文档。上一次我们发现ScheduleActivity只能被调用一次，那麽明显的解决方桉就是允许一个States上可以有很多的Delegates。看着states.Frames，我们过往的实现都只会盯着最上层的一个Frames，但是在并行的情况下这样就不成了。我们需要一个像Stack一样，但是有很多个顶的一个数据结构，想一想，这不就是一颗反过来的树吗？我们会在数据结构上放这个棵树所有的叶，然后用父指针去找它的Parent Frame。当我们有很多的叶的时候，只有States就不够了。Activity.Execute将无法知道它应该是在那一个Frame上跑，所以我们要把Execute的参数从States改成Frame，这样的话其它就会变得简单了。 </P>
<P><A href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/cnflow/WindowsLiveWriter/d5ccad671cc7_91E4/7-to-8_2.png" original-url="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/d5ccad671cc7_91E4/7-to-8_2.png" mce_href="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/d5ccad671cc7_91E4/7-to-8_2.png"><IMG style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; DISPLAY: block; FLOAT: none; MARGIN-LEFT: auto; BORDER-TOP: 0px; MARGIN-RIGHT: auto; BORDER-RIGHT: 0px" title=7-to-8 border=0 alt=7-to-8 src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/cnflow/WindowsLiveWriter/d5ccad671cc7_91E4/7-to-8_thumb.png" original-url="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/d5ccad671cc7_91E4/7-to-8_thumb.png" width=948 height=613 mce_src="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/d5ccad671cc7_91E4/7-to-8_thumb.png"></A> </P>
<P>代碼示例：Version 8 </P>
<P>我们还是在使用以前的Activity，这只不过是为了安全起见，我们没有使用并行。现在我们使用并行了，最简单的就是Parallel，它只会Schedule两个Read。 <BR></P>
<P><A href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/cnflow/WindowsLiveWriter/d5ccad671cc7_91E4/8-to-9_2.png" original-url="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/d5ccad671cc7_91E4/8-to-9_2.png" mce_href="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/d5ccad671cc7_91E4/8-to-9_2.png"><IMG style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; DISPLAY: block; FLOAT: none; MARGIN-LEFT: auto; BORDER-TOP: 0px; MARGIN-RIGHT: auto; BORDER-RIGHT: 0px" title=8-to-9 border=0 alt=8-to-9 src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/cnflow/WindowsLiveWriter/d5ccad671cc7_91E4/8-to-9_thumb.png" original-url="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/d5ccad671cc7_91E4/8-to-9_thumb.png" width=948 height=690 mce_src="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/d5ccad671cc7_91E4/8-to-9_thumb.png"></A> </P>
<P>代碼示例：Version 9 </P>
<P>留意工作还是单线程的在执行。Parallel只不过允许多份工作同时在等着而已。当这些工作实际上是在等外界输入，那它们就是在同时等待。在上一个版本，我们每一个Delegate的先决条件都是Frame，但是很多时候有些工作不能完成不是因为其它工作还没完成，而只不过是它所需要的资料还没到而已。这些资料到最终还是从主程序中获得。我们可以通过States去通知主程序去接收资料，到资料收到的时候，主程序便能执行正在等待数据的工作了。WF3使用Queue的方式去等待数据，但我们发现很多时候我们只需要一个数据项，所以WF4使用了Bookmark。 <BR></P>
<P><A href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/cnflow/WindowsLiveWriter/d5ccad671cc7_91E4/9-to-10_2.png" original-url="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/d5ccad671cc7_91E4/9-to-10_2.png" mce_href="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/d5ccad671cc7_91E4/9-to-10_2.png"><IMG style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; DISPLAY: block; FLOAT: none; MARGIN-LEFT: auto; BORDER-TOP: 0px; MARGIN-RIGHT: auto; BORDER-RIGHT: 0px" title=9-to-10 border=0 alt=9-to-10 src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/cnflow/WindowsLiveWriter/d5ccad671cc7_91E4/9-to-10_thumb.png" original-url="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/d5ccad671cc7_91E4/9-to-10_thumb.png" width=1026 height=683 mce_src="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/d5ccad671cc7_91E4/9-to-10_thumb.png"></A> </P>
<P>代碼示例：Version １０ </P>
<P>到这里我们就结束我们这旅程了。当然，要做到像今天的WF4还有很漫长的路，但是我希望通过这几篇，大家可以瞭解WF的使计，并可以好好的把它运用到实际场景里，谢谢。</P>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/09/99/69/95/HomeMadeWF.zip" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-09-99-69-95/HomeMadeWF.zip">HomeMadeWF.zip</a></p>]]></content:encoded>
    </item>
    <item>
      <title>工作流内部工作原理（二）</title>
      <link>https://docs.microsoft.com/archive/blogs/cnflow/93</link>
      <pubDate>Thu, 15 Apr 2010 19:15:00 GMT</pubDate>
      <dc:creator><![CDATA[andrewau]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/cnflow/2010/04/15/93/</guid>
      <description><![CDATA[接续上一篇，我们会去分离程序和资料。对程序员来说，程序和资料是非常不一样的概念。比如说，你可以执行程序，却不可以执行资料。程序代码在执行过程中不会被修改（除了少数比如hook或者overlay的例子除...]]></description>
      <content:encoded><![CDATA[<P>接续上一篇，我们会去分离程序和资料。对程序员来说，程序和资料是非常不一样的概念。比如说，你可以执行程序，却不可以执行资料。程序代码在执行过程中不会被修改（除了少数比如hook或者overlay的例子除外），但是资料却没有这样的限制，甚至我们觉得资料常常被修改是再正常不过。对于处理器来说，它们并没有多大的区别，都是一堆bytes。从一个操作系统的角度去看，代码不会修改这一点可以用来优化内存的使用，因为代码只要存一份就够了，可以用来起几个进程。 </P>
<P>同样的道理也可以使用在Workflow上。我们做这样的比喻，Sequence就是程序，但是sequenceCounter只不过是执行资料而已。sequenceCounter这个成员定义在Sequence上使它们不可区分。想像同样的一个Sequence有很多个进程在跑，那么sequenceCounter就会乱掉。 </P>
<P>读一下Activity这个类的代码，States定义在Activity上其实是个更大的问题。与其让States通过activity去读取，我们会把它变成一个Execute的参数。同样地,NextDelegate也不应该放在Activity上。不过这个问题更麻烦一点，因为Sequence需要同时有两个NextDelegate。去解决这个问题，我们会使用一个Stack&lt;Frame&gt;去存这些NextDelegate物件。勤快的读者们，请你们亲手试一试，因为我们在下一个版本会有很多的改动如下 <BR><A href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/cnflow/WindowsLiveWriter/53285c1dd367_9032/5-to-6_2.png" original-url="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/53285c1dd367_9032/5-to-6_2.png" mce_href="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/53285c1dd367_9032/5-to-6_2.png"><IMG style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; DISPLAY: block; FLOAT: none; MARGIN-LEFT: auto; BORDER-TOP: 0px; MARGIN-RIGHT: auto; BORDER-RIGHT: 0px" title=5-to-6 border=0 alt=5-to-6 src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/cnflow/WindowsLiveWriter/53285c1dd367_9032/5-to-6_thumb.png" original-url="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/53285c1dd367_9032/5-to-6_thumb.png" width=975 height=573 mce_src="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/53285c1dd367_9032/5-to-6_thumb.png"></A> </P>
<P>代碼示例: Version 6 </P>
<P>我尝试把Version 6和Version 5的改动减到最少了，在把delegate的存取方式改动的同时，我们也优化了Sequence的执行。现在执行Sequence下的Activity再也不会通过Sequence。现在的代码能跑了，我们就该重构。这次我希望States把它的Stack&lt;Frame&gt;给封装起来。这样这个Stack的逻辑就不会四处分散。说也不是很难，只要把Frame变成private就可以驱动这些重构了，我做的不过就是给操作一个合适的名字而已。 </P>
<P>Version 7 没有甚麽实质改动，只是封装一下而已。 <BR>代碼示例: Version 7 </P>
<P>现在我们已经很接近了，在这个版本里我们只对States做序列化。我们问一下自己，到底我们做完程序和资料的分离没有？答桉是没有，因为States里有Delegate，而delegate又回到Activity物件，即程序。我们可以通过序列化MethodInfo，而非delegate，去达到这一点。我们在序列化MethodInfo的同时，也需要存ActivityID。ActivityID是一个Activity的唯一身份码，我们可以通过深度搜寻去找出来。由于这些代码比较複杂，也没有甚麽太大的技术难点，在这里我们就轻轻带过了。另外一个问题就是我们没有保证程序是唯读的。这问题有多种解决的办法。在WF3中它採取了先拷贝一份，永远拷贝来执行的方法，而WF4则选择做一个拷贝（只拷贝对执行有作用的资料），跑原来的一份，而在跑的时候保证跑的确实是原来的拷贝。我们也可以选择当用户更新程序时让它出错。同样地，这些都比较明显，就略过不写了。 </P>
<P>还有另外一个问题，就是一行的程序(比喻为一个Activity)可以被多次执行。最简单的例子就是迴圈。这时候，它们的储存必须定义在Frame上，实际上，所有的资料都应该存在Frame上，这就没有States的全局性了，这是WF4比它前一个版本优胜的地方。 </P>
<P>看着States的实现，我们不难发现ScheduleActivity只能被调用一次，因为Frame上只有一个NextDelegate成员。下一篇我们会去改进ScheduleActivity,允许多个未完成的Activity，我们也会讲一讲如何让Workflow和主程序如何使用Bookmark通讯。</P>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/09/99/69/92/HomeMadeWF.zip" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-09-99-69-92/HomeMadeWF.zip">HomeMadeWF.zip</a></p>]]></content:encoded>
    </item>
    <item>
      <title>工作流内部工作原理（一）</title>
      <link>https://docs.microsoft.com/archive/blogs/cnflow/103</link>
      <pubDate>Thu, 15 Apr 2010 19:09:00 GMT</pubDate>
      <dc:creator><![CDATA[andrewau]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/cnflow/2010/04/15/103/</guid>
      <description><![CDATA[读过了Essential Windows Workflow...]]></description>
      <content:encoded><![CDATA[<P>读过了Essential Windows Workflow Foundation这本书后，我觉得有必要为WF4也写一课。其实，WF4的工作原理和它的前一个版本几乎一模一样，但是它们的编程模型却是很不一样。我们会从可序列化的委托(Serializable Delegate)开始，慢慢深入去看WF4的设计。 </P>
<P>首先我们先看一下CLR里对Continuation的支持吧。Continuation是一个程序执行中一个可以保存的时间点，所以它必须保存一个对执行代码的指针，而delegate就是一种这样的指针。Delegate最棒的地方就是它可以被序列化，反序列化，然后继续执行。我们可以看一下以下的代码： </P>
<P>代碼示例: SerializableDelegate </P>
<P>可序列化delegate给了我们一个方法去暂停一个线程，然后让它在另外一个进程中继续，这个进程甚至可以是在另外一台电脑上。这样做的好处很多，而最重要的就是我们除掉了所有的「亲和度」，代码再不依赖于进程，甚至不依赖于电脑。这样的话我们就可以很好的扩展我们的系统，只需要多买电脑，也任务分派到不同的机器就可以，关键是代码可以随时停下来。同时，我们有了控制。我们可以把序列化了的delegate删掉，这样就可以取消了这个进程。工作可以暂停很长的时间，而不用担心系统会佔用了内存资源。接下来我们看一下以下的代码示例，看看我们如何使用可序列化delegate把一个程序拆成不同的进程： </P>
<P>代碼示例: Version 1 </P>
<P>执行这程序三遍，你会发现在控制台上会显示出“Hello world to homemade workflow foundation!”。在以上的代码，我们就简单的创建了一个简单的工作流程序了。不用说，这个范例有很多问题，我们有很多可以改善它的地方。第一步我们就先把对可扩展性的支持和业务逻辑分离出来。我们会提炼一个名为ReadReadWrite的类，然后把业务逻辑集中在它上面，这样我们就写了Version 2 </P>
<P><A href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/1-to-2_2.png" original-url="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/1-to-2_2.png" mce_href="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/1-to-2_2.png"><IMG style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; DISPLAY: block; FLOAT: none; MARGIN-LEFT: auto; BORDER-TOP: 0px; MARGIN-RIGHT: auto; BORDER-RIGHT: 0px" title=1-to-2 border=0 alt=1-to-2 src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/1-to-2_thumb.png" original-url="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/1-to-2_thumb.png" width=604 height=262 mce_src="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/1-to-2_thumb.png"></A> </P>
<P>代碼示例: Version 2 </P>
<P>首先，留意我在主程序中写了一个while循环，这个只是一个方便的捷径而已。对于我们来说，知道这些程序能够分开就好，实在没有必要真的分开执行。这次的重构其实很简单直接，不过有一点值的留意的就是我把NextDelegate变成一个ReadReadWrite的一个成员。这样做的原因是为了让每一个delegate都有一样的signature. </P>
<P>到了这个时候，主程序和业务逻辑已经是分离了。我们还是有一些耦合点，例如主程序需要知道程序的起点是RunStep1，而储存接续点的成员是NextDelegate,这样我们的主程序就不能是一个普遍而适用于任何程序的主程序。去掉这些耦合的方法说也简单，就是定义一个父类，让主程序与父类耦合而不会和业务逻辑耦合，这个父类我们命名成Activity. </P>
<P><A href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/2-to-3_2.png" original-url="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/2-to-3_2.png" mce_href="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/2-to-3_2.png"><IMG style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; DISPLAY: block; FLOAT: none; MARGIN-LEFT: auto; BORDER-TOP: 0px; MARGIN-RIGHT: auto; BORDER-RIGHT: 0px" title=2-to-3 border=0 alt=2-to-3 src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/2-to-3_thumb.png" original-url="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/2-to-3_thumb.png" width=604 height=454 mce_src="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/2-to-3_thumb.png"></A> </P>
<P>代碼示例: Version 3 </P>
<P>这次的重构也是非常的简单。读一下ReadReadWrite的代码，这样的代码已经不难写。其中有一点我们不喜欢的地方就是Execute和RunStep2里面做的事情几乎一模一样，从代码的角度去看最好我们可以重用。我们试着提炼，然后发现两个问题。一个是它们是在更新不同的状态变量，而另外一个是它们返回不同的delegate。它们返回不同delegate的这问题尤其严重，因为读文件和程序执行顺序是两件垂直的事情。我们把程序控制和实际工作混合在一起会破坏了代码的内聚性。接下来我们试着把它们区分出来。 </P>
<P><A href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/3-to-4_2.png" original-url="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/3-to-4_2.png" mce_href="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/3-to-4_2.png"><IMG style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; DISPLAY: block; FLOAT: none; MARGIN-LEFT: auto; BORDER-TOP: 0px; MARGIN-RIGHT: auto; BORDER-RIGHT: 0px" title=3-to-4 border=0 alt=3-to-4 src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/3-to-4_thumb.png" original-url="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/3-to-4_thumb.png" width=713 height=573 mce_src="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/3-to-4_thumb.png"></A> </P>
<P>代碼示例: Version 4 </P>
<P>Sequence activity 的实现一点也不简单，而且它也不是最优化的。下一篇我们会讨如何优化Sequence。现在我们先专注于除掉Read1和Read2之间的重覆。到这里Read1和Read2都是在读文件了，所以我们可以通过名字去找状态变量，这样就可以完全的把重覆除掉了。 </P>
<P><A href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/4-to-5_2.png" original-url="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/4-to-5_2.png" mce_href="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/4-to-5_2.png"><IMG style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; DISPLAY: block; FLOAT: none; MARGIN-LEFT: auto; BORDER-TOP: 0px; MARGIN-RIGHT: auto; BORDER-RIGHT: 0px" title=4-to-5 border=0 alt=4-to-5 src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/4-to-5_thumb.png" original-url="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/4-to-5_thumb.png" width=961 height=574 mce_src="https://blogs.msdn.com/blogfiles/cnflow/WindowsLiveWriter/435b03cbfaf6_8EC5/4-to-5_thumb.png"></A> </P>
<P>代碼示例: Version 5 </P>
<P>走到这里，我们已经可以写能重用的Activity，而且这些Activity都不用管有关序列化的细节。不去读Main的代码，我们甚至不知道序列化有实际进行。看看Read和Write，是不是开始有点像WF4里Activity的API呢？下一篇，我们会继续这个例子，去探讨为甚麽Activity.Execute会有一个参数，和这个参数如何把程序兴资料区分出来。</P>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/09/99/69/89/HomeMadeWF.zip" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-09-99-69-89/HomeMadeWF.zip">HomeMadeWF.zip</a></p>]]></content:encoded>
    </item>
    <item>
      <title>WorkflowInvoker，WorkflowApplication和WorkflowServiceHost</title>
      <link>https://docs.microsoft.com/archive/blogs/cnflow/workflowinvokerworkflowapplicationworkflowservicehost</link>
      <pubDate>Wed, 03 Feb 2010 18:08:14 GMT</pubDate>
      <dc:creator><![CDATA[Hong Wang]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/cnflow/2010/02/03/workflowinvokerworkflowapplicationworkflowservicehost/</guid>
      <description><![CDATA[Workflow 4.0是个全新的框架，重写了3.0/3.5中的的Runtime和Activity。在Workflow...]]></description>
      <content:encoded><![CDATA[<p>Workflow 4.0是个全新的框架，重写了3.0/3.5中的的Runtime和Activity。在Workflow 4.0的Runtime和3.0/3.5中的Runtime的最大区别在于没有了WorkflowRuntime对应的类。 </p>  <p>在3.0/3.5中，我们需要先初始化WorkflowRuntime，并通过CreateInstance函数来建立工作流实例（WorkflowInstance）。4.0中的WorkflowApplication类和WorkflowInstance类对应，但是不需要通过WorkflowRuntime来实例化，可以通过new来实例化。 </p>  <p>虽然WorkflowApplication和WorkflowInstance的对应，但是他们的构造方法也存在区别。3.0/3.5中我们通过传入一个System.Type类，由WorkflowRuntime来负责进行模板的实例化。而在4.0中我们是传入一个System.Activities.Activity实例来建立工作流实例。 </p>  <p>除此之外，4.0中还提供提供了一种调用Workflow的快速通道WorkflowInvoker。可以直接通过调用静态方法Invoke来执行一个工作流。 </p>  <p>Workflow 4.0另一个重大的特点在于WCF和Workflow的密切结合。和3.5一样，4.0中存在一个用于管理Workflow服务的类System.ServiceModel.Activities.WorkflowServiceHost。需要注意的是这个类存在于System.ServiceModel.Activities.dll中。他和System.WorkflowService.dll （.NET Framework 3.5）中的WorkflowServiceHost是完全不同的。 </p>  <p>由此可见4.0中提供了3中不同的方式来管理/托管工作流实例。</p>  <p><strong><font size="3">WorkflowInvoker </font></strong></p>  <p>可以像执行一个函数一样运行一个工作流。 </p>  <p>优点：简单 </p>  <p>缺点：在工作流执行过程中，如果和工作流实例进行数据交换 </p>  <p>代码： </p>  <p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; WorkflowInvoker.Invoke(new Workflow1());</p>  <p><font size="3"><strong>WorkflowApplication </strong></font></p>  <p>可以控制工作流实例长时间运行，可以在运行过程中和实例进行数据交换。但是只能执行一个的工作流实例。 </p>  <p>优点： </p>  <p>支持持久化，可以对实例进行控制，可以通过Bookmark来控制实例或交换数据。 </p>  <p>应用例子： </p>  <p>使用工作流辅助建立一个向导的UI程序。 </p>  <p>代码： </p>  <p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; WorkflowApplication instance = new WorkflowApplication(new Workflow1()); </p>  <p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; instance.Completed = delegate(WorkflowApplicationCompletedEventArgs e) </p>  <p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; { </p>  <p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Console.WriteLine(&quot;workflow completed, Id = &quot; + instance.Id); </p>  <p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }; </p>  <p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; instance.Run(); </p>  <p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; //.... </p>  <p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; instance.ResumeBookmark(&quot;Submit&quot;, data); </p>  <p><strong><font size="3">WorkflowServiceHost </font></strong></p>  <p>WorkflowServiceHost是一个最主要的工作流主机类。可以同时管理多个工作流实例，同时控制实例的激活等操作。支持WCF，和3.5相比有更强大的消息关联功能。当然WorkflowServiceHost也支持持久化（Persistence）和跟踪（Tracking）等功能。</p>]]></content:encoded>
    </item>
    <item>
      <title>Workflow 4.0中的Variable和Argument</title>
      <link>https://docs.microsoft.com/archive/blogs/cnflow/workflow-4-0variableargument</link>
      <pubDate>Tue, 02 Feb 2010 03:31:00 GMT</pubDate>
      <dc:creator><![CDATA[Hong Wang]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/cnflow/2010/02/02/workflow-4-0variableargument/</guid>
      <description><![CDATA[还是那句老话，Workflow 4.0和Workflow 3.0/3.5相比有很大的不同，其中之一就是Activity间数据交换方式的变化。...]]></description>
      <content:encoded><![CDATA[<P>还是那句老话，Workflow 4.0和Workflow 3.0/3.5相比有很大的不同，其中之一就是Activity间数据交换方式的变化。 </P>
<P>在3.0/3.5中，我们使用DependenceProperty，使用绑定的方式在不同的Property建立关联，由此实现数据的交换。这种方式的确很灵活，但是也带来不少弊病。比如所有的数据都存在同一个域中导致性能的下降，同时DependenceProperty的生命周期也是很让人困惑的问题，我不只一次的在论坛上听到有人提出对DependenceProperty的初始化时间提出疑问。 </P>
<P>在4.0中，我们建立了一种更简洁的数据管理模式，变量（Variable）和参数（Argument）。这也是一种更符合大部分人编程习惯的数据模型。在传统的编程模式中，我们使用变量来存储数据，使用函数来封装程序的功能，使用参数和返回值来进行函数间的数据交换。 </P>
<P>在Workflow中，Activity是封装功能的单元，我们可以理解为传统编程中的函数。而变量、参数的概念是类似的。我们来看一个例子。 </P>
<P>一个C#的Hello World只有几行</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:0f1080c9-167e-413e-b63b-aae7633a6401 class=wlWriterEditableSmartContent>
<DIV style="BORDER-BOTTOM: #000080 1px solid; BORDER-LEFT: #000080 1px solid; FONT-FAMILY: 'Courier New', Courier, Monospace; COLOR: #000; FONT-SIZE: 10pt; BORDER-TOP: #000080 1px solid; BORDER-RIGHT: #000080 1px solid">
<DIV style="PADDING-BOTTOM: 2px; PADDING-LEFT: 5px; PADDING-RIGHT: 5px; FONT-FAMILY: Verdana, Tahoma, Arial, sans-serif; BACKGROUND: #000080; COLOR: #fff; FONT-WEIGHT: bold; PADDING-TOP: 2px">C#的Hello World</DIV>
<DIV style="BACKGROUND: #ddd; MAX-HEIGHT: 300px; OVERFLOW: auto">
<OL style="PADDING-BOTTOM: 0px; MARGIN: 0px 0px 0px 2em; PADDING-LEFT: 5px; PADDING-RIGHT: 0px; BACKGROUND: #ffffff; PADDING-TOP: 0px">
<LI><SPAN style="COLOR: #0000ff">void</SPAN> HelloWorldSample()&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">{&nbsp;&nbsp;&nbsp;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">string</SPAN> message = <SPAN style="COLOR: #a31515">"Hello World"</SPAN>;&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(message);&nbsp;&nbsp;&nbsp;</LI>
<LI>}</LI></OL></DIV></DIV></DIV>
<P>在这个例子中我们建立了一个message变量，它的生命周期就是我们的HelloWorldSample这个函数，在函数开始时我们会对这个变量进行初始化，结束时会释放这个变量的资源。同时我们调用了一个叫做WriteLine的函数，这个函数有一个输入参数类型是string，在调用函数时我们将变量message作为具体的值传入WriteLine函数。如果将上面的代码转化为Workflow，你会发现这些概念是对应的。 </P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:864ed0f7-ddda-4bdd-bc0e-3d6f90c43b50 class=wlWriterEditableSmartContent>
<DIV style="BORDER-BOTTOM: #000080 1px solid; BORDER-LEFT: #000080 1px solid; FONT-FAMILY: 'Courier New', Courier, Monospace; COLOR: #000; FONT-SIZE: 10pt; BORDER-TOP: #000080 1px solid; BORDER-RIGHT: #000080 1px solid">
<DIV style="PADDING-BOTTOM: 2px; PADDING-LEFT: 5px; PADDING-RIGHT: 5px; FONT-FAMILY: Verdana, Tahoma, Arial, sans-serif; BACKGROUND: #000080; COLOR: #fff; FONT-WEIGHT: bold; PADDING-TOP: 2px">Workflow Hello World</DIV>
<DIV style="BACKGROUND: #ddd; MAX-HEIGHT: 300px; OVERFLOW: auto">
<OL style="PADDING-BOTTOM: 0px; MARGIN: 0px 0px 0px 2.5em; PADDING-LEFT: 5px; PADDING-RIGHT: 0px; BACKGROUND: #ffffff; PADDING-TOP: 0px">
<LI><SPAN style="COLOR: #2b91af">Sequence</SPAN> seq = <SPAN style="COLOR: #0000ff">new</SPAN> <SPAN style="COLOR: #2b91af">Sequence</SPAN>()</LI>
<LI style="BACKGROUND: #f3f3f3">{</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;DisplayName = <SPAN style="COLOR: #a31515">"HelloWorldSample"</SPAN>,</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;Variables =&nbsp;&nbsp;&nbsp;&nbsp;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">new</SPAN> <SPAN style="COLOR: #2b91af">Variable</SPAN>&lt;<SPAN style="COLOR: #0000ff">string</SPAN>&gt;()&nbsp;&nbsp;&nbsp;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Name = <SPAN style="COLOR: #a31515">"message"</SPAN>,&nbsp;&nbsp;&nbsp;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default = <SPAN style="COLOR: #a31515">"Hello World"</SPAN>,&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},&nbsp;&nbsp;&nbsp;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;},</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;Activities =&nbsp;&nbsp;&nbsp;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">new</SPAN> <SPAN style="COLOR: #2b91af">WriteLine</SPAN>()&nbsp;&nbsp;&nbsp;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Text = <SPAN style="COLOR: #0000ff">new</SPAN> <SPAN style="COLOR: #2b91af">InArgument</SPAN>&lt;<SPAN style="COLOR: #0000ff">string</SPAN>&gt;(<SPAN style="COLOR: #0000ff">new</SPAN> <SPAN style="COLOR: #2b91af">VisualBasicValue</SPAN>&lt;<SPAN style="COLOR: #0000ff">string</SPAN>&gt;(<SPAN style="COLOR: #a31515">"[message]"</SPAN>)),&nbsp;&nbsp;&nbsp;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;}</LI>
<LI>};</LI></OL></DIV></DIV></DIV>
<P>下面我们来具体介绍Variable和Argument。 </P>
<P><STRONG><FONT color=#0000ff size=4>参数（Argument），Activity的I/O数据流接口</FONT></STRONG></P>
<P>Argument是Activity的I/O接口，分为InArgument、OutArgument、InOutArgument。 </P>
<P>可见域：定义Argument的Activity的Execute函数及其所有实现子活动（Implementation Child Activity ）。 </P>
<P>生命周期：等同于定义它的Activity。 </P>
<P><FONT size=2><STRONG>InArgument </STRONG></FONT></P>
<P>用于向Activity传入数据，只能对其进行取值操作。它可以使用Activity&lt;T&gt;、常数、Lambda Expression或者Variable作为表达式。 </P>
<P><STRONG><FONT size=2>OutArgument</FONT></STRONG> </P>
<P>用于向Activity外部传出数据，只能对其进行赋值操作。它可以使用Activity&lt;Location&lt;T&gt;&gt;、Lambda Expression或者Variable作为表达式。 </P>
<P><FONT size=2><STRONG>InOutArgument</STRONG></FONT> </P>
<P>用于向Activity传入或传出数据，可对其进行取值和赋值操作。它可以使用Activity&lt;Location&lt;T&gt;&gt;、Lambda Expression或者Variable作为表达式。 </P>
<P><FONT size=2><STRONG>RequiredArgumentAttribute</STRONG></FONT> </P>
<P>默认情况下，在使用Activity时不需要对每一个Argument赋值，但是你可以为你的 Argument加上RequiredArgumentAttribute，用于表示必须在定义Workflow时必须为这个Argument赋初值。Runtime在创建Workflow实例时会对所有Argument进行检测，如果某个RequiredArgument没有赋值，将会抛出ValidationException。 </P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:c7d31d86-f11d-4fb9-be99-0a86e639b46e class=wlWriterEditableSmartContent>
<DIV style="BORDER-BOTTOM: #000080 1px solid; BORDER-LEFT: #000080 1px solid; FONT-FAMILY: 'Courier New', Courier, Monospace; COLOR: #000; FONT-SIZE: 10pt; BORDER-TOP: #000080 1px solid; BORDER-RIGHT: #000080 1px solid">
<DIV style="PADDING-BOTTOM: 2px; PADDING-LEFT: 5px; PADDING-RIGHT: 5px; FONT-FAMILY: Verdana, Tahoma, Arial, sans-serif; BACKGROUND: #000080; COLOR: #fff; FONT-WEIGHT: bold; PADDING-TOP: 2px">范例：使用Argument</DIV>
<DIV style="BACKGROUND: #ddd; MAX-HEIGHT: 300px; OVERFLOW: auto">
<OL style="PADDING-BOTTOM: 0px; MARGIN: 0px 0px 0px 2.5em; PADDING-LEFT: 5px; PADDING-RIGHT: 0px; BACKGROUND: #ffffff; PADDING-TOP: 0px">
<LI><SPAN style="COLOR: #0000ff">public</SPAN> <SPAN style="COLOR: #0000ff">sealed</SPAN> <SPAN style="COLOR: #0000ff">class</SPAN> <SPAN style="COLOR: #2b91af">Increment</SPAN> : <SPAN style="COLOR: #2b91af">CodeActivity</SPAN></LI>
<LI style="BACKGROUND: #f3f3f3">{</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">public</SPAN> <SPAN style="COLOR: #2b91af">InArgument</SPAN>&lt;<SPAN style="COLOR: #0000ff">int</SPAN>&gt; Input { <SPAN style="COLOR: #0000ff">get</SPAN>; <SPAN style="COLOR: #0000ff">set</SPAN>; }</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">public</SPAN> <SPAN style="COLOR: #2b91af">OutArgument</SPAN>&lt;<SPAN style="COLOR: #0000ff">int</SPAN>&gt; Output { <SPAN style="COLOR: #0000ff">get</SPAN>; <SPAN style="COLOR: #0000ff">set</SPAN>; }</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">protected</SPAN> <SPAN style="COLOR: #0000ff">override</SPAN> <SPAN style="COLOR: #0000ff">void</SPAN> Execute(<SPAN style="COLOR: #2b91af">CodeActivityContext</SPAN> context)</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;{</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">this</SPAN>.Output.Set(context, <SPAN style="COLOR: #0000ff">this</SPAN>.Input.Get(context) + 1);</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;}</LI>
<LI>}</LI>
<LI style="BACKGROUND: #f3f3f3"></LI>
<LI><SPAN style="COLOR: #0000ff">public</SPAN> <SPAN style="COLOR: #0000ff">sealed</SPAN> <SPAN style="COLOR: #0000ff">class</SPAN> <SPAN style="COLOR: #2b91af">Increment</SPAN> : <SPAN style="COLOR: #2b91af">CodeActivity</SPAN></LI>
<LI style="BACKGROUND: #f3f3f3">{</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">public</SPAN> <SPAN style="COLOR: #2b91af">InOutArgument</SPAN>&lt;<SPAN style="COLOR: #0000ff">int</SPAN>&gt; Value { <SPAN style="COLOR: #0000ff">get</SPAN>; <SPAN style="COLOR: #0000ff">set</SPAN>; }</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">protected</SPAN> <SPAN style="COLOR: #0000ff">override</SPAN> <SPAN style="COLOR: #0000ff">void</SPAN> Execute(<SPAN style="COLOR: #2b91af">CodeActivityContext</SPAN> context)</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;{</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">this</SPAN>.Value.Set(context, <SPAN style="COLOR: #0000ff">this</SPAN>.Value.Get(context) + 1);</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;}</LI>
<LI style="BACKGROUND: #f3f3f3">}</LI></OL></DIV></DIV></DIV>
<P><FONT color=#0000ff size=3><STRONG>变量（Variable），Workflow中的数据公共存储单元</STRONG></FONT></P>
<P>Variable是用于存放数据的单元，Variable分为普通变量（Variable）实现变量（Implementation Variable）两种。 </P>
<P>生命周期：等同于定义它的Activity，在Activity开始执行时， Workflow Runtime会初始化所有定义在这个Activity中的变量，而在Activity结束时结束Variable的生命周期。 </P>
<P><FONT color=#ff0000 size=3><STRONG><EM>注意：</EM></STRONG></FONT> </P>
<P><EM>Variable的初始化是有顺序的，如果你不清楚当前 Activity对Variable的初始化顺序，不建议使用同一个Activity中定义的不同Variable进行相互的初始化。因为这种错误无法在设计时别检测，只有在运行时才能被发现。</EM> </P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:442d37d4-04c3-4552-b1ec-c65f6dc2358c class=wlWriterEditableSmartContent>
<DIV style="BORDER-BOTTOM: #000080 1px solid; BORDER-LEFT: #000080 1px solid; FONT-FAMILY: 'Courier New', Courier, Monospace; COLOR: #000; FONT-SIZE: 10pt; BORDER-TOP: #000080 1px solid; BORDER-RIGHT: #000080 1px solid">
<DIV style="PADDING-BOTTOM: 2px; PADDING-LEFT: 5px; PADDING-RIGHT: 5px; FONT-FAMILY: Verdana, Tahoma, Arial, sans-serif; BACKGROUND: #000080; COLOR: #fff; FONT-WEIGHT: bold; PADDING-TOP: 2px">一个错误的例子</DIV>
<DIV style="BACKGROUND: #ddd; MAX-HEIGHT: 300px; OVERFLOW: auto">
<OL style="PADDING-BOTTOM: 0px; MARGIN: 0px 0px 0px 2.5em; PADDING-LEFT: 5px; PADDING-RIGHT: 0px; BACKGROUND: #ffffff; PADDING-TOP: 0px">
<LI><SPAN style="COLOR: #2b91af">Sequence</SPAN> sequence = <SPAN style="COLOR: #0000ff">new</SPAN> <SPAN style="COLOR: #2b91af">Sequence</SPAN>()</LI>
<LI style="BACKGROUND: #f3f3f3">{</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;Variables =&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">new</SPAN> <SPAN style="COLOR: #2b91af">Variable</SPAN>&lt;<SPAN style="COLOR: #0000ff">string</SPAN>&gt;()&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Name = <SPAN style="COLOR: #a31515">"var1"</SPAN>,&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default = <SPAN style="COLOR: #0000ff">new</SPAN> <SPAN style="COLOR: #2b91af">VisualBasicValue</SPAN>&lt;<SPAN style="COLOR: #0000ff">string</SPAN>&gt;(<SPAN style="COLOR: #a31515">"[var2]"</SPAN>),&nbsp;&nbsp;&nbsp;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">new</SPAN> <SPAN style="COLOR: #2b91af">Variable</SPAN>&lt;<SPAN style="COLOR: #0000ff">string</SPAN>&gt;()&nbsp;&nbsp;&nbsp;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Name = <SPAN style="COLOR: #a31515">"var2"</SPAN>,&nbsp;&nbsp;&nbsp;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default = <SPAN style="COLOR: #0000ff">new</SPAN> <SPAN style="COLOR: #2b91af">VisualBasicValue</SPAN>&lt;<SPAN style="COLOR: #0000ff">string</SPAN>&gt;(<SPAN style="COLOR: #a31515">"\"Hello\""</SPAN>),&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},&nbsp;&nbsp;&nbsp;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;},</LI>
<LI style="BACKGROUND: #f3f3f3">};</LI></OL></DIV></DIV></DIV>
<P mce_keep="true">&nbsp;</P>
<P mce_keep="true">&nbsp;</P>
<P>因为var2在var1之后初始化，所以在运行时会得到异常说var1没有被初始化。但是如果你交换var1和var2的位置，就不会得到任何异常。</P>
<P>Variable的默认值的类型是System.Activites.Activity&lt;T&gt;。但你还可以用常数、Lambda Expression或者其他得Variable来初始化Variable。除了类型（Type），名称（Name）和默认值（DefaultValue），Variable还有两个附加属性：只读（ReadOnly）和映射（Mapped） </P>
<P><FONT size=3><STRONG>只读（ReadOnly）</STRONG></FONT> </P>
<P>ReadOnly属性顾名思义，就是表示这个Variable在能在初始化时对其赋值，若试图在之后对其赋值，将会得到一个运行时的异常。 </P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:9368cebc-bf73-49b2-bd39-ad49244566f2 class=wlWriterEditableSmartContent>
<DIV style="BORDER-BOTTOM: #000080 1px solid; BORDER-LEFT: #000080 1px solid; FONT-FAMILY: 'Courier New', Courier, Monospace; COLOR: #000; FONT-SIZE: 10pt; BORDER-TOP: #000080 1px solid; BORDER-RIGHT: #000080 1px solid">
<DIV style="PADDING-BOTTOM: 2px; PADDING-LEFT: 5px; PADDING-RIGHT: 5px; FONT-FAMILY: Verdana, Tahoma, Arial, sans-serif; BACKGROUND: #000080; COLOR: #fff; FONT-WEIGHT: bold; PADDING-TOP: 2px">对ReadOnly的Variable赋值</DIV>
<DIV style="BACKGROUND: #ddd; MAX-HEIGHT: 300px; OVERFLOW: auto">
<OL style="PADDING-BOTTOM: 0px; MARGIN: 0px 0px 0px 2.5em; PADDING-LEFT: 5px; PADDING-RIGHT: 0px; BACKGROUND: #ffffff; PADDING-TOP: 0px">
<LI><SPAN style="COLOR: #2b91af">Sequence</SPAN> seq = <SPAN style="COLOR: #0000ff">new</SPAN> <SPAN style="COLOR: #2b91af">Sequence</SPAN>()&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">{&nbsp;&nbsp;&nbsp;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;Variables =&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">new</SPAN> <SPAN style="COLOR: #2b91af">Variable</SPAN>&lt;<SPAN style="COLOR: #0000ff">int</SPAN>&gt;()&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Name = <SPAN style="COLOR: #a31515">"data"</SPAN>,&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default = <SPAN style="COLOR: #0000ff">new</SPAN> <SPAN style="COLOR: #2b91af">VisualBasicValue</SPAN>&lt;<SPAN style="COLOR: #0000ff">int</SPAN>&gt;(<SPAN style="COLOR: #a31515">"123"</SPAN>),&nbsp;&nbsp;&nbsp;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Modifiers = <SPAN style="COLOR: #2b91af">VariableModifiers</SPAN>.ReadOnly,&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;},&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;Activities =&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">new</SPAN> <SPAN style="COLOR: #2b91af">Assign</SPAN>&lt;<SPAN style="COLOR: #0000ff">int</SPAN>&gt;()&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;To = <SPAN style="COLOR: #0000ff">new</SPAN> <SPAN style="COLOR: #2b91af">VisualBasicReference</SPAN>&lt;<SPAN style="COLOR: #0000ff">int</SPAN>&gt;(<SPAN style="COLOR: #a31515">"[data]"</SPAN>),&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Value = <SPAN style="COLOR: #0000ff">new</SPAN> <SPAN style="COLOR: #2b91af">VisualBasicValue</SPAN>&lt;<SPAN style="COLOR: #0000ff">int</SPAN>&gt;(<SPAN style="COLOR: #a31515">"345"</SPAN>),&nbsp;&nbsp;&nbsp;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;},&nbsp;&nbsp;&nbsp;</LI>
<LI>};</LI></OL></DIV></DIV></DIV>
<P>以上Workflow会在运行时Assign时获得一个InvalidOperationException。</P>
<P><FONT size=3><STRONG>映射（Mapped）</STRONG></FONT> </P>
<P>被标志为Mapped属性的Variable，可在工作流实例持久化时对这个Variable进行查询，在此我就不详细展开了。</P>
<P><STRONG><FONT color=#0000ff size=4>普通变量（Variable）</FONT></STRONG></P>
<P>一个典型的例子是Sequence得Variables属性。</P>
<P>可见域：定义Variable的Activity的所有普通子活动（Child Activity）。</P>
<P><FONT color=#ff0000 size=3><STRONG><EM>注意： </EM></STRONG></FONT></P>
<P><EM>你是无法在Activity的内部函数中或其实现子活动（Implementation Child Activity）中使用当前Activity所定义的普通变量。</EM></P>
<P>下面是一个在自定义活动中使用Variable的例子： 
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:c915b2c9-8d48-4937-9013-118755fc953a class=wlWriterEditableSmartContent>
<DIV style="BORDER-BOTTOM: #000080 1px solid; BORDER-LEFT: #000080 1px solid; FONT-FAMILY: 'Courier New', Courier, Monospace; COLOR: #000; FONT-SIZE: 10pt; BORDER-TOP: #000080 1px solid; BORDER-RIGHT: #000080 1px solid">
<DIV style="PADDING-BOTTOM: 2px; PADDING-LEFT: 5px; PADDING-RIGHT: 5px; FONT-FAMILY: Verdana, Tahoma, Arial, sans-serif; BACKGROUND: #000080; COLOR: #fff; FONT-WEIGHT: bold; PADDING-TOP: 2px">范例</DIV>
<DIV style="BACKGROUND: #ddd; MAX-HEIGHT: 500px; OVERFLOW: auto">
<OL style="PADDING-BOTTOM: 0px; MARGIN: 0px 0px 0px 2.5em; PADDING-LEFT: 5px; PADDING-RIGHT: 0px; BACKGROUND: #ffffff; PADDING-TOP: 0px">
<LI><SPAN style="COLOR: #0000ff">public</SPAN> <SPAN style="COLOR: #0000ff">sealed</SPAN> <SPAN style="COLOR: #0000ff">class</SPAN> <SPAN style="COLOR: #2b91af">WriteVariable</SPAN> : <SPAN style="COLOR: #2b91af">NativeActivity</SPAN></LI>
<LI style="BACKGROUND: #f3f3f3">{</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">private</SPAN> <SPAN style="COLOR: #2b91af">Collection</SPAN>&lt;<SPAN style="COLOR: #2b91af">Variable</SPAN>&gt; variables;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">public</SPAN> <SPAN style="COLOR: #2b91af">Collection</SPAN>&lt;<SPAN style="COLOR: #2b91af">Variable</SPAN>&gt; Variables</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;{</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">get</SPAN></LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">if</SPAN> (<SPAN style="COLOR: #0000ff">this</SPAN>.variables == <SPAN style="COLOR: #0000ff">null</SPAN>)</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">this</SPAN>.variables = <SPAN style="COLOR: #0000ff">new</SPAN> <SPAN style="COLOR: #2b91af">Collection</SPAN>&lt;<SPAN style="COLOR: #2b91af">Variable</SPAN>&gt;();</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">return</SPAN> <SPAN style="COLOR: #0000ff">this</SPAN>.variables;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;}</LI>
<LI></LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">protected</SPAN> <SPAN style="COLOR: #0000ff">override</SPAN> <SPAN style="COLOR: #0000ff">void</SPAN> CacheMetadata(<SPAN style="COLOR: #2b91af">NativeActivityMetadata</SPAN> metadata)</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;{</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;metadata.SetVariablesCollection(<SPAN style="COLOR: #0000ff">this</SPAN>.Variables);</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">base</SPAN>.CacheMetadata(metadata);</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;}</LI>
<LI></LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">protected</SPAN> <SPAN style="COLOR: #0000ff">override</SPAN> <SPAN style="COLOR: #0000ff">void</SPAN> Execute(<SPAN style="COLOR: #2b91af">NativeActivityContext</SPAN> context)</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;{</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">foreach</SPAN> (<SPAN style="COLOR: #2b91af">Variable</SPAN> var <SPAN style="COLOR: #0000ff">in</SPAN> <SPAN style="COLOR: #0000ff">this</SPAN>.Variables)</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #2b91af">Console</SPAN>.WriteLine(var.Name);</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #008000">//注意：公共变量是无法在定义它的Activity中使用的</SPAN></LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #008000">//因此你无法执行</SPAN></LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #008000">//Console.WriteLine(var.Get(context));&nbsp;&nbsp;&nbsp;</SPAN></LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;}</LI>
<LI style="BACKGROUND: #f3f3f3">}</LI></OL></DIV></DIV></DIV>
<P><FONT color=#0000ff size=4><STRONG>实现变量（Implementation Variable）</STRONG></FONT> </P>
<P>Implantation Variable用于储存Activity的私有数据，它只能在定义它的Activity的内部函数中或Activity的实现子活动（Implementation Child Activity）中使用。 </P>
<P>可见域：定义Variable的Activity的内部函数和所有实现子活动（Implementation Child Activity）。 </P>
<P>下面是一个使用Implementation Variable的例子：</P>
<DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:488e8cae-0185-43fe-9b16-3cecee358365 class=wlWriterEditableSmartContent>
<DIV style="BORDER-BOTTOM: #000080 1px solid; BORDER-LEFT: #000080 1px solid; FONT-FAMILY: 'Courier New', Courier, Monospace; COLOR: #000; FONT-SIZE: 10pt; BORDER-TOP: #000080 1px solid; BORDER-RIGHT: #000080 1px solid">
<DIV style="PADDING-BOTTOM: 2px; PADDING-LEFT: 5px; PADDING-RIGHT: 5px; FONT-FAMILY: Verdana, Tahoma, Arial, sans-serif; BACKGROUND: #000080; COLOR: #fff; FONT-WEIGHT: bold; PADDING-TOP: 2px">范例</DIV>
<DIV style="BACKGROUND: #ddd; MAX-HEIGHT: 1000px; OVERFLOW: auto">
<OL style="PADDING-BOTTOM: 0px; MARGIN: 0px 0px 0px 2.5em; PADDING-LEFT: 5px; PADDING-RIGHT: 0px; BACKGROUND: #ffffff; PADDING-TOP: 0px">
<LI><SPAN style="COLOR: #0000ff">public</SPAN> <SPAN style="COLOR: #0000ff">sealed</SPAN> <SPAN style="COLOR: #0000ff">class</SPAN> <SPAN style="COLOR: #2b91af">SimpleSequence</SPAN> : <SPAN style="COLOR: #2b91af">NativeActivity</SPAN></LI>
<LI style="BACKGROUND: #f3f3f3">{</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #2b91af">Collection</SPAN>&lt;<SPAN style="COLOR: #2b91af">Activity</SPAN>&gt; activities;</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #2b91af">Variable</SPAN>&lt;<SPAN style="COLOR: #0000ff">int</SPAN>&gt; lastIndex;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #2b91af">CompletionCallback</SPAN> onChildComplete;</LI>
<LI style="BACKGROUND: #f3f3f3"></LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">public</SPAN> SimpleSequence()</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;: <SPAN style="COLOR: #0000ff">base</SPAN>()</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;{</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">this</SPAN>.lastIndex = <SPAN style="COLOR: #0000ff">new</SPAN> <SPAN style="COLOR: #2b91af">Variable</SPAN>&lt;<SPAN style="COLOR: #0000ff">int</SPAN>&gt;();</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">this</SPAN>.onChildComplete = <SPAN style="COLOR: #0000ff">new</SPAN> <SPAN style="COLOR: #2b91af">CompletionCallback</SPAN>(ChildComplete);</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;}</LI>
<LI></LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">public</SPAN> <SPAN style="COLOR: #2b91af">Collection</SPAN>&lt;<SPAN style="COLOR: #2b91af">Activity</SPAN>&gt; Activities</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;{</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">get</SPAN></LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">if</SPAN> (<SPAN style="COLOR: #0000ff">this</SPAN>.activities == <SPAN style="COLOR: #0000ff">null</SPAN>)</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">this</SPAN>.activities = <SPAN style="COLOR: #0000ff">new</SPAN> <SPAN style="COLOR: #2b91af">Collection</SPAN>&lt;<SPAN style="COLOR: #2b91af">Activity</SPAN>&gt;();</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">return</SPAN> <SPAN style="COLOR: #0000ff">this</SPAN>.activities;</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;}</LI>
<LI></LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">protected</SPAN> <SPAN style="COLOR: #0000ff">override</SPAN> <SPAN style="COLOR: #0000ff">void</SPAN> CacheMetadata(<SPAN style="COLOR: #2b91af">NativeActivityMetadata</SPAN> metadata)</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;{</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;metadata.SetChildrenCollection(<SPAN style="COLOR: #0000ff">this</SPAN>.Activities);</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;metadata.AddImplementationVariable(<SPAN style="COLOR: #0000ff">this</SPAN>.lastIndex);</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;}</LI>
<LI></LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">protected</SPAN> <SPAN style="COLOR: #0000ff">override</SPAN> <SPAN style="COLOR: #0000ff">void</SPAN> Execute(<SPAN style="COLOR: #2b91af">NativeActivityContext</SPAN> context)</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;{</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">if</SPAN> (<SPAN style="COLOR: #0000ff">this</SPAN>.activities != <SPAN style="COLOR: #0000ff">null</SPAN> &amp;&amp; <SPAN style="COLOR: #0000ff">this</SPAN>.Activities.Count &gt; 0)</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;context.ScheduleActivity(<SPAN style="COLOR: #0000ff">this</SPAN>.Activities[0], <SPAN style="COLOR: #0000ff">this</SPAN>.onChildComplete);</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;}</LI>
<LI></LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">void</SPAN> ChildComplete(<SPAN style="COLOR: #2b91af">NativeActivityContext</SPAN> context, <SPAN style="COLOR: #2b91af">ActivityInstance</SPAN> completedInstance)</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;{</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">int</SPAN> nextChildIndex = <SPAN style="COLOR: #0000ff">this</SPAN>.lastIndex.Get(context) + 1;</LI>
<LI></LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">if</SPAN> (nextChildIndex &lt; <SPAN style="COLOR: #0000ff">this</SPAN>.Activities.Count)</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;context.ScheduleActivity(<SPAN style="COLOR: #0000ff">this</SPAN>.Activities[nextChildIndex], <SPAN style="COLOR: #0000ff">this</SPAN>.onChildComplete);</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN style="COLOR: #0000ff">this</SPAN>.lastIndex.Set(context, nextChildIndex);</LI>
<LI style="BACKGROUND: #f3f3f3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;}</LI>
<LI style="BACKGROUND: #f3f3f3">}</LI></OL></DIV></DIV></DIV>]]></content:encoded>
    </item>
  </channel>
</rss>