共用方式為


操作說明:取消資料流程區塊

本文件示範如何在您的應用程式中啟用取消作業。 此範例會使用 Windows Forms 來顯示工作項目在資料流程管線中的作用位置,以及取消作業的效果。

注意

TPL 資料流程程式庫 (System.Threading.Tasks.Dataflow 命名空間) 並未隨 .NET 散發。 若要在 Visual Studio 中安裝 System.Threading.Tasks.Dataflow 命名空間,請開啟您的專案,從 [專案] 功能表中選擇 [管理 NuGet 套件],並於線上搜尋 System.Threading.Tasks.Dataflow 套件。 除此之外也可使用 .Net Core CLI (執行 dotnet add package System.Threading.Tasks.Dataflow) 加以安裝。

若要建立 Windows Forms 應用程式

  1. 建立 C# 或 Visual Basic Windows Forms 應用程式專案。 在下列步驟中,專案會命名為 CancellationWinForms

  2. 在主要表單 Form1.cs (在 Visual Basic 中為 Form1.vb) 的表單設計工具上,新增 ToolStrip 控制項。

  3. ToolStripButton 控制項加入 ToolStrip 控制項。 將 DisplayStyle 屬性設為 Text 並將 Text 屬性設為新增工作項目

  4. 將第二個 ToolStripButton 控制項加入 ToolStrip 控制項。 將 DisplayStyle 屬性設為 Text,將 Text 屬性設為 Cancel,然後將 Enabled 屬性設為 False

  5. 將四個 ToolStripProgressBar 物件加入 ToolStrip 控制項。

建立資料流程管線

本節說明如何建立資料流程管線,以處理工作項目並更新進度列。

建立資料流程管線

  1. 在您的專案中,加入 System.Threading.Tasks.Dataflow.dll 的參考。

  2. 確定 Form1.cs (Form1.vb for Visual Basic) 包含下列 using 指示詞 (Imports 在 Visual Basic 中)。

    using System;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Threading.Tasks.Dataflow;
    using System.Windows.Forms;
    
    Imports System.Threading
    Imports System.Threading.Tasks
    Imports System.Threading.Tasks.Dataflow
    
    
  3. WorkItem 類別新增為 Form1 類別的內部類別。

    // A placeholder type that performs work.
    class WorkItem
    {
       // Performs work for the provided number of milliseconds.
       public void DoWork(int milliseconds)
       {
          // For demonstration, suspend the current thread.
          Thread.Sleep(milliseconds);
       }
    }
    
    ' A placeholder type that performs work.
    Private Class WorkItem
        ' Performs work for the provided number of milliseconds.
        Public Sub DoWork(ByVal milliseconds As Integer)
            ' For demonstration, suspend the current thread.
            Thread.Sleep(milliseconds)
        End Sub
    End Class
    
  4. 將下列資料成員新增至 Form1 類別。

    // Enables the user interface to signal cancellation.
    CancellationTokenSource cancellationSource;
    
    // The first node in the dataflow pipeline.
    TransformBlock<WorkItem, WorkItem> startWork;
    
    // The second, and final, node in the dataflow pipeline.
    ActionBlock<WorkItem> completeWork;
    
    // Increments the value of the provided progress bar.
    ActionBlock<ToolStripProgressBar> incrementProgress;
    
    // Decrements the value of the provided progress bar.
    ActionBlock<ToolStripProgressBar> decrementProgress;
    
    // Enables progress bar actions to run on the UI thread.
    TaskScheduler uiTaskScheduler;
    
    ' Enables the user interface to signal cancellation.
    Private cancellationSource As CancellationTokenSource
    
    ' The first node in the dataflow pipeline.
    Private startWork As TransformBlock(Of WorkItem, WorkItem)
    
    ' The second, and final, node in the dataflow pipeline.
    Private completeWork As ActionBlock(Of WorkItem)
    
    ' Increments the value of the provided progress bar.
    Private incrementProgress As ActionBlock(Of ToolStripProgressBar)
    
    ' Decrements the value of the provided progress bar.
    Private decrementProgress As ActionBlock(Of ToolStripProgressBar)
    
    ' Enables progress bar actions to run on the UI thread.
    Private uiTaskScheduler As TaskScheduler
    
  5. 將下列 CreatePipeline 方法新增至 Form1 類別。

    // Creates the blocks that participate in the dataflow pipeline.
    private void CreatePipeline()
    {
       // Create the cancellation source.
       cancellationSource = new CancellationTokenSource();
    
       // Create the first node in the pipeline.
       startWork = new TransformBlock<WorkItem, WorkItem>(workItem =>
       {
          // Perform some work.
          workItem.DoWork(250);
    
          // Decrement the progress bar that tracks the count of
          // active work items in this stage of the pipeline.
          decrementProgress.Post(toolStripProgressBar1);
    
          // Increment the progress bar that tracks the count of
          // active work items in the next stage of the pipeline.
          incrementProgress.Post(toolStripProgressBar2);
    
          // Send the work item to the next stage of the pipeline.
          return workItem;
       },
       new ExecutionDataflowBlockOptions
       {
          CancellationToken = cancellationSource.Token
       });
    
       // Create the second, and final, node in the pipeline.
       completeWork = new ActionBlock<WorkItem>(workItem =>
       {
          // Perform some work.
          workItem.DoWork(1000);
    
          // Decrement the progress bar that tracks the count of
          // active work items in this stage of the pipeline.
          decrementProgress.Post(toolStripProgressBar2);
    
          // Increment the progress bar that tracks the overall
          // count of completed work items.
          incrementProgress.Post(toolStripProgressBar3);
       },
       new ExecutionDataflowBlockOptions
       {
          CancellationToken = cancellationSource.Token,
          MaxDegreeOfParallelism = 2
       });
    
       // Connect the two nodes of the pipeline. When the first node completes,
       // set the second node also to the completed state.
       startWork.LinkTo(
          completeWork, new DataflowLinkOptions { PropagateCompletion = true });
    
       // Create the dataflow action blocks that increment and decrement
       // progress bars.
       // These blocks use the task scheduler that is associated with
       // the UI thread.
    
       incrementProgress = new ActionBlock<ToolStripProgressBar>(
          progressBar => progressBar.Value++,
          new ExecutionDataflowBlockOptions
          {
             CancellationToken = cancellationSource.Token,
             TaskScheduler = uiTaskScheduler
          });
    
       decrementProgress = new ActionBlock<ToolStripProgressBar>(
          progressBar => progressBar.Value--,
          new ExecutionDataflowBlockOptions
          {
             CancellationToken = cancellationSource.Token,
             TaskScheduler = uiTaskScheduler
          });
    }
    
    ' Creates the blocks that participate in the dataflow pipeline.
    Private Sub CreatePipeline()
        ' Create the cancellation source.
        cancellationSource = New CancellationTokenSource()
    
        ' Create the first node in the pipeline.
        startWork = New TransformBlock(Of WorkItem, WorkItem)(Function(workItem)
                                                                  ' Perform some work.
                                                                  ' Decrement the progress bar that tracks the count of
                                                                  ' active work items in this stage of the pipeline.
                                                                  ' Increment the progress bar that tracks the count of
                                                                  ' active work items in the next stage of the pipeline.
                                                                  ' Send the work item to the next stage of the pipeline.
                                                                  workItem.DoWork(250)
                                                                  decrementProgress.Post(toolStripProgressBar1)
                                                                  incrementProgress.Post(toolStripProgressBar2)
                                                                  Return workItem
                                                              End Function,
        New ExecutionDataflowBlockOptions With {.CancellationToken = cancellationSource.Token})
    
        ' Create the second, and final, node in the pipeline.
        completeWork = New ActionBlock(Of WorkItem)(Sub(workItem)
                                                        ' Perform some work.
                                                        ' Decrement the progress bar that tracks the count of
                                                        ' active work items in this stage of the pipeline.
                                                        ' Increment the progress bar that tracks the overall
                                                        ' count of completed work items.
                                                        workItem.DoWork(1000)
                                                        decrementProgress.Post(toolStripProgressBar2)
                                                        incrementProgress.Post(toolStripProgressBar3)
                                                    End Sub,
        New ExecutionDataflowBlockOptions With {.CancellationToken = cancellationSource.Token,
                                                .MaxDegreeOfParallelism = 2})
    
        ' Connect the two nodes of the pipeline. When the first node completes,
        ' set the second node also to the completed state.
        startWork.LinkTo(
           completeWork, New DataflowLinkOptions With {.PropagateCompletion = true})
    
        ' Create the dataflow action blocks that increment and decrement
        ' progress bars.
        ' These blocks use the task scheduler that is associated with
        ' the UI thread.
    
        incrementProgress = New ActionBlock(Of ToolStripProgressBar)(
           Sub(progressBar) progressBar.Value += 1,
           New ExecutionDataflowBlockOptions With {.CancellationToken = cancellationSource.Token,
                                                   .TaskScheduler = uiTaskScheduler})
    
        decrementProgress = New ActionBlock(Of ToolStripProgressBar)(
           Sub(progressBar) progressBar.Value -= 1,
           New ExecutionDataflowBlockOptions With {.CancellationToken = cancellationSource.Token,
                                                   .TaskScheduler = uiTaskScheduler})
    
    End Sub
    

由於 incrementProgressdecrementProgress資料流程區塊會在使用者介面上進行處理,因此這個動作一定要在使用者介面執行緒上發生。 為了要完成這項作業,這些物件在建構時會提供 ExecutionDataflowBlockOptions 物件,而且其 TaskScheduler 屬性會設定為 TaskScheduler.FromCurrentSynchronizationContextTaskScheduler.FromCurrentSynchronizationContext 方法會建立 TaskScheduler 物件,該物件會在目前的同步處理內容上執行工作。 由於 Form1 建構函式是從使用者介面執行緒呼叫,因此 incrementProgressdecrementProgress 資料流程區塊的動作也會在使用者介面執行緒上執行。

此範例在它建構管線成員時會設定 CancellationToken 屬性。 因為 CancellationToken 屬性會永久取消資料流程區塊執行,所以必須在使用者取消此作業,而後想要將更多工作項目新增至管線之後,重新建立整個管線。 如需示範取消資料流程區塊的替代方式,以便在取消作業後執行其他工作的範例,請參閱逐步解說︰在 Windows Forms 應用程式中使用資料流程

將資料流程管線連接至使用者介面

本節說明如何將資料流程管線連接至使用者介面。 建立管線以及將工作項目新增至管線都是由 [新增工作項目] 按鈕的事件處理常式所控制。 取消作業是由 [取消] 按鈕所起始。 當使用者按一下任一個按鈕時,會以非同步方式起始適當的動作。

將資料流程管線連接至使用者介面

  1. 在主要表單的表單設計工具上,為 [新增工作項目]Click 事件建立事件處理常式。

  2. 實作 [新增工作項目] 按鈕的 Click 事件。

    // Event handler for the Add Work Items button.
    private void toolStripButton1_Click(object sender, EventArgs e)
    {
       // The Cancel button is disabled when the pipeline is not active.
       // Therefore, create the pipeline and enable the Cancel button
       // if the Cancel button is disabled.
       if (!toolStripButton2.Enabled)
       {
          CreatePipeline();
    
          // Enable the Cancel button.
          toolStripButton2.Enabled = true;
       }
    
       // Post several work items to the head of the pipeline.
       for (int i = 0; i < 5; i++)
       {
          toolStripProgressBar1.Value++;
          startWork.Post(new WorkItem());
       }
    }
    
    ' Event handler for the Add Work Items button.
    Private Sub toolStripButton1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles toolStripButton1.Click
        ' The Cancel button is disabled when the pipeline is not active.
        ' Therefore, create the pipeline and enable the Cancel button
        ' if the Cancel button is disabled.
        If Not toolStripButton2.Enabled Then
            CreatePipeline()
    
            ' Enable the Cancel button.
            toolStripButton2.Enabled = True
        End If
    
        ' Post several work items to the head of the pipeline.
        For i As Integer = 0 To 4
            toolStripProgressBar1.Value += 1
            startWork.Post(New WorkItem())
        Next i
    End Sub
    
  3. 在主要表單的表單設計工具上,為 [取消]Click 事件建立事件處理常式。

  4. 實作 [取消] 按鈕的 Click 事件處理常式。

    // Event handler for the Cancel button.
    private async void toolStripButton2_Click(object sender, EventArgs e)
    {
       // Disable both buttons.
       toolStripButton1.Enabled = false;
       toolStripButton2.Enabled = false;
    
       // Trigger cancellation.
       cancellationSource.Cancel();
    
       try
       {
          // Asynchronously wait for the pipeline to complete processing and for
          // the progress bars to update.
          await Task.WhenAll(
             completeWork.Completion,
             incrementProgress.Completion,
             decrementProgress.Completion);
       }
       catch (OperationCanceledException)
       {
       }
    
       // Increment the progress bar that tracks the number of cancelled
       // work items by the number of active work items.
       toolStripProgressBar4.Value += toolStripProgressBar1.Value;
       toolStripProgressBar4.Value += toolStripProgressBar2.Value;
    
       // Reset the progress bars that track the number of active work items.
       toolStripProgressBar1.Value = 0;
       toolStripProgressBar2.Value = 0;
    
       // Enable the Add Work Items button.
       toolStripButton1.Enabled = true;
    }
    
    ' Event handler for the Cancel button.
    Private Async Sub toolStripButton2_Click(ByVal sender As Object, ByVal e As EventArgs) Handles toolStripButton2.Click
        ' Disable both buttons.
        toolStripButton1.Enabled = False
        toolStripButton2.Enabled = False
    
        ' Trigger cancellation.
        cancellationSource.Cancel()
    
        Try
            ' Asynchronously wait for the pipeline to complete processing and for
            ' the progress bars to update.
            Await Task.WhenAll(completeWork.Completion, incrementProgress.Completion, decrementProgress.Completion)
        Catch e1 As OperationCanceledException
        End Try
    
        ' Increment the progress bar that tracks the number of cancelled
        ' work items by the number of active work items.
        toolStripProgressBar4.Value += toolStripProgressBar1.Value
        toolStripProgressBar4.Value += toolStripProgressBar2.Value
    
        ' Reset the progress bars that track the number of active work items.
        toolStripProgressBar1.Value = 0
        toolStripProgressBar2.Value = 0
    
        ' Enable the Add Work Items button.
        toolStripButton1.Enabled = True
    End Sub
    

範例

下列範例顯示 Form1.cs (在 Visual Basic 中為 Form1.vb) 的完整程式碼。

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
using System.Windows.Forms;

namespace CancellationWinForms
{
   public partial class Form1 : Form
   {
      // A placeholder type that performs work.
      class WorkItem
      {
         // Performs work for the provided number of milliseconds.
         public void DoWork(int milliseconds)
         {
            // For demonstration, suspend the current thread.
            Thread.Sleep(milliseconds);
         }
      }

      // Enables the user interface to signal cancellation.
      CancellationTokenSource cancellationSource;

      // The first node in the dataflow pipeline.
      TransformBlock<WorkItem, WorkItem> startWork;

      // The second, and final, node in the dataflow pipeline.
      ActionBlock<WorkItem> completeWork;

      // Increments the value of the provided progress bar.
      ActionBlock<ToolStripProgressBar> incrementProgress;

      // Decrements the value of the provided progress bar.
      ActionBlock<ToolStripProgressBar> decrementProgress;

      // Enables progress bar actions to run on the UI thread.
      TaskScheduler uiTaskScheduler;

      public Form1()
      {
         InitializeComponent();

         // Create the UI task scheduler from the current synchronization
         // context.
         uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
      }

      // Creates the blocks that participate in the dataflow pipeline.
      private void CreatePipeline()
      {
         // Create the cancellation source.
         cancellationSource = new CancellationTokenSource();

         // Create the first node in the pipeline.
         startWork = new TransformBlock<WorkItem, WorkItem>(workItem =>
         {
            // Perform some work.
            workItem.DoWork(250);

            // Decrement the progress bar that tracks the count of
            // active work items in this stage of the pipeline.
            decrementProgress.Post(toolStripProgressBar1);

            // Increment the progress bar that tracks the count of
            // active work items in the next stage of the pipeline.
            incrementProgress.Post(toolStripProgressBar2);

            // Send the work item to the next stage of the pipeline.
            return workItem;
         },
         new ExecutionDataflowBlockOptions
         {
            CancellationToken = cancellationSource.Token
         });

         // Create the second, and final, node in the pipeline.
         completeWork = new ActionBlock<WorkItem>(workItem =>
         {
            // Perform some work.
            workItem.DoWork(1000);

            // Decrement the progress bar that tracks the count of
            // active work items in this stage of the pipeline.
            decrementProgress.Post(toolStripProgressBar2);

            // Increment the progress bar that tracks the overall
            // count of completed work items.
            incrementProgress.Post(toolStripProgressBar3);
         },
         new ExecutionDataflowBlockOptions
         {
            CancellationToken = cancellationSource.Token,
            MaxDegreeOfParallelism = 2
         });

         // Connect the two nodes of the pipeline. When the first node completes,
         // set the second node also to the completed state.
         startWork.LinkTo(
            completeWork, new DataflowLinkOptions { PropagateCompletion = true });

         // Create the dataflow action blocks that increment and decrement
         // progress bars.
         // These blocks use the task scheduler that is associated with
         // the UI thread.

         incrementProgress = new ActionBlock<ToolStripProgressBar>(
            progressBar => progressBar.Value++,
            new ExecutionDataflowBlockOptions
            {
               CancellationToken = cancellationSource.Token,
               TaskScheduler = uiTaskScheduler
            });

         decrementProgress = new ActionBlock<ToolStripProgressBar>(
            progressBar => progressBar.Value--,
            new ExecutionDataflowBlockOptions
            {
               CancellationToken = cancellationSource.Token,
               TaskScheduler = uiTaskScheduler
            });
      }

      // Event handler for the Add Work Items button.
      private void toolStripButton1_Click(object sender, EventArgs e)
      {
         // The Cancel button is disabled when the pipeline is not active.
         // Therefore, create the pipeline and enable the Cancel button
         // if the Cancel button is disabled.
         if (!toolStripButton2.Enabled)
         {
            CreatePipeline();

            // Enable the Cancel button.
            toolStripButton2.Enabled = true;
         }

         // Post several work items to the head of the pipeline.
         for (int i = 0; i < 5; i++)
         {
            toolStripProgressBar1.Value++;
            startWork.Post(new WorkItem());
         }
      }

      // Event handler for the Cancel button.
      private async void toolStripButton2_Click(object sender, EventArgs e)
      {
         // Disable both buttons.
         toolStripButton1.Enabled = false;
         toolStripButton2.Enabled = false;

         // Trigger cancellation.
         cancellationSource.Cancel();

         try
         {
            // Asynchronously wait for the pipeline to complete processing and for
            // the progress bars to update.
            await Task.WhenAll(
               completeWork.Completion,
               incrementProgress.Completion,
               decrementProgress.Completion);
         }
         catch (OperationCanceledException)
         {
         }

         // Increment the progress bar that tracks the number of cancelled
         // work items by the number of active work items.
         toolStripProgressBar4.Value += toolStripProgressBar1.Value;
         toolStripProgressBar4.Value += toolStripProgressBar2.Value;

         // Reset the progress bars that track the number of active work items.
         toolStripProgressBar1.Value = 0;
         toolStripProgressBar2.Value = 0;

         // Enable the Add Work Items button.
         toolStripButton1.Enabled = true;
      }

      ~Form1()
      {
         cancellationSource.Dispose();
      }
   }
}
Imports System.Threading
Imports System.Threading.Tasks
Imports System.Threading.Tasks.Dataflow


Namespace CancellationWinForms
    Partial Public Class Form1
        Inherits Form
        ' A placeholder type that performs work.
        Private Class WorkItem
            ' Performs work for the provided number of milliseconds.
            Public Sub DoWork(ByVal milliseconds As Integer)
                ' For demonstration, suspend the current thread.
                Thread.Sleep(milliseconds)
            End Sub
        End Class

        ' Enables the user interface to signal cancellation.
        Private cancellationSource As CancellationTokenSource

        ' The first node in the dataflow pipeline.
        Private startWork As TransformBlock(Of WorkItem, WorkItem)

        ' The second, and final, node in the dataflow pipeline.
        Private completeWork As ActionBlock(Of WorkItem)

        ' Increments the value of the provided progress bar.
        Private incrementProgress As ActionBlock(Of ToolStripProgressBar)

        ' Decrements the value of the provided progress bar.
        Private decrementProgress As ActionBlock(Of ToolStripProgressBar)

        ' Enables progress bar actions to run on the UI thread.
        Private uiTaskScheduler As TaskScheduler

        Public Sub New()
            InitializeComponent()

            ' Create the UI task scheduler from the current synchronization
            ' context.
            uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()
        End Sub

        ' Creates the blocks that participate in the dataflow pipeline.
        Private Sub CreatePipeline()
            ' Create the cancellation source.
            cancellationSource = New CancellationTokenSource()

            ' Create the first node in the pipeline.
            startWork = New TransformBlock(Of WorkItem, WorkItem)(Function(workItem)
                                                                      ' Perform some work.
                                                                      ' Decrement the progress bar that tracks the count of
                                                                      ' active work items in this stage of the pipeline.
                                                                      ' Increment the progress bar that tracks the count of
                                                                      ' active work items in the next stage of the pipeline.
                                                                      ' Send the work item to the next stage of the pipeline.
                                                                      workItem.DoWork(250)
                                                                      decrementProgress.Post(toolStripProgressBar1)
                                                                      incrementProgress.Post(toolStripProgressBar2)
                                                                      Return workItem
                                                                  End Function,
            New ExecutionDataflowBlockOptions With {.CancellationToken = cancellationSource.Token})

            ' Create the second, and final, node in the pipeline.
            completeWork = New ActionBlock(Of WorkItem)(Sub(workItem)
                                                            ' Perform some work.
                                                            ' Decrement the progress bar that tracks the count of
                                                            ' active work items in this stage of the pipeline.
                                                            ' Increment the progress bar that tracks the overall
                                                            ' count of completed work items.
                                                            workItem.DoWork(1000)
                                                            decrementProgress.Post(toolStripProgressBar2)
                                                            incrementProgress.Post(toolStripProgressBar3)
                                                        End Sub,
            New ExecutionDataflowBlockOptions With {.CancellationToken = cancellationSource.Token,
                                                    .MaxDegreeOfParallelism = 2})

            ' Connect the two nodes of the pipeline. When the first node completes,
            ' set the second node also to the completed state.
            startWork.LinkTo(
               completeWork, New DataflowLinkOptions With {.PropagateCompletion = true})

            ' Create the dataflow action blocks that increment and decrement
            ' progress bars.
            ' These blocks use the task scheduler that is associated with
            ' the UI thread.

            incrementProgress = New ActionBlock(Of ToolStripProgressBar)(
               Sub(progressBar) progressBar.Value += 1,
               New ExecutionDataflowBlockOptions With {.CancellationToken = cancellationSource.Token,
                                                       .TaskScheduler = uiTaskScheduler})

            decrementProgress = New ActionBlock(Of ToolStripProgressBar)(
               Sub(progressBar) progressBar.Value -= 1,
               New ExecutionDataflowBlockOptions With {.CancellationToken = cancellationSource.Token,
                                                       .TaskScheduler = uiTaskScheduler})

        End Sub

        ' Event handler for the Add Work Items button.
        Private Sub toolStripButton1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles toolStripButton1.Click
            ' The Cancel button is disabled when the pipeline is not active.
            ' Therefore, create the pipeline and enable the Cancel button
            ' if the Cancel button is disabled.
            If Not toolStripButton2.Enabled Then
                CreatePipeline()

                ' Enable the Cancel button.
                toolStripButton2.Enabled = True
            End If

            ' Post several work items to the head of the pipeline.
            For i As Integer = 0 To 4
                toolStripProgressBar1.Value += 1
                startWork.Post(New WorkItem())
            Next i
        End Sub

        ' Event handler for the Cancel button.
        Private Async Sub toolStripButton2_Click(ByVal sender As Object, ByVal e As EventArgs) Handles toolStripButton2.Click
            ' Disable both buttons.
            toolStripButton1.Enabled = False
            toolStripButton2.Enabled = False

            ' Trigger cancellation.
            cancellationSource.Cancel()

            Try
                ' Asynchronously wait for the pipeline to complete processing and for
                ' the progress bars to update.
                Await Task.WhenAll(completeWork.Completion, incrementProgress.Completion, decrementProgress.Completion)
            Catch e1 As OperationCanceledException
            End Try

            ' Increment the progress bar that tracks the number of cancelled
            ' work items by the number of active work items.
            toolStripProgressBar4.Value += toolStripProgressBar1.Value
            toolStripProgressBar4.Value += toolStripProgressBar2.Value

            ' Reset the progress bars that track the number of active work items.
            toolStripProgressBar1.Value = 0
            toolStripProgressBar2.Value = 0

            ' Enable the Add Work Items button.
            toolStripButton1.Enabled = True
        End Sub

        Protected Overrides Sub Finalize()
            cancellationSource.Dispose()
            MyBase.Finalize()
        End Sub
    End Class
End Namespace

下圖顯示執行的應用程式。

Windows Forms 應用程式

另請參閱