title: Safe ThreadPool Queueing with Parameters in VB.NET (WinForms)
body: <p>I know how to use BackgroundWorker (gui object in WinForms designer), and to manually instantiate Threads that elevate the custom event to the UI, however, I am having some trouble figuring out how to use the ThreadPool object (simplest form) to handle elevating an event to the form for "safe" UI manipulation.</p>
  
  <p>Example is as follows :</p>
  
  <h2>Form1.vb</h2>
  
  <pre><code>    Public Class Form1
          WithEvents t As Tools = New Tools
  
          Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
              t.Unzip("file 1", "foo")
              t.Unzip("file 2", "foo")
              t.Unzip("file 3", "foo")
              t.Unzip("file 4", "foo")
              t.Unzip("file 5", "foo")
              t.Unzip("file 6", "foo")
              t.Unzip("file 7", "foo")
              t.Unzip("file 8", "foo")
              t.Unzip("file 9", "foo")
  
          End Sub
  
          Private Sub t_UnzipComplete(ZipInfo As Tools.ZipInfo) Handles t.UnzipComplete
              TextBox1.Text = TextBox1.Text &amp; ZipInfo.ZipFile &amp; vbCr
          End Sub
      End Class
  </code></pre>
  
  <p>( add a multiline textbox, and a button to this form for the demo )</p>
  
  <h2>Tools.vb</h2>
  
  <pre><code>    Imports System
      Imports System.Threading
      Imports System.IO.Compression
  
      Public Class Tools
      #Region "Zip"
          Private _zip As System.IO.Compression.ZipFile
          Public Shared Event UnzipComplete(ByVal ZipInfo As ZipInfo)
          Public Shared Event ZipComplete(ByVal ZipInfo As ZipInfo)
  
          Public Class ZipInfo
              Public Property ZipFile As String
              Public Property Path As String
          End Class
  
  
          Public Sub Unzip(ByVal ZipFile As String, ByVal Destination As String)
              Dim _ZipInfo As New Tools.ZipInfo
              _ZipInfo.ZipFile = ZipFile
              _ZipInfo.Path = Destination
              ThreadPool.QueueUserWorkItem(AddressOf ThreadUnzip, _ZipInfo)
          End Sub
  
          Public Sub Zip(ByVal Folder As String, ByVal ZipFile As String)
              Dim _ZipInfo As New Tools.ZipInfo
              _ZipInfo.ZipFile = ZipFile
              _ZipInfo.Path = Folder
              ThreadPool.QueueUserWorkItem(AddressOf ThreadUnzip, _ZipInfo)
          End Sub
  
          Shared Sub ThreadUnzip(ZipInfo As Object)
              RaiseEvent UnzipComplete(ZipInfo)
          End Sub
  
          Shared Sub ThreadZip(ZipInfo As Object)
              RaiseEvent ZipComplete(ZipInfo)
          End Sub
  
      #End Region
  
      End Class
  </code></pre>
  
  <p>What this code should do, is as follows :</p>
  
  <ul>
  <li>On Button1_Click, add 9 items to the ThreadPool</li>
  <li>On each thread completion (order is irrelevant), raise an event that elevates to Form1</li>
  </ul>
  
  <p>The event being raised on Form1 should be UI safe, so I can use the information being passed to the ZipCompleted / UnzipCompleted events in the Textbox.  This should be generic, meaning the function that raises the event should be reusable and does not make calls to the form directly. (aka, I do not want a "custom" sub or function in Tools.vb that calls specific elements on Form1.vb . This should be generic and reusable by adding the class to my project and then entering any "custom" form code under the event being raised  (like when Button1_Click is raised, even though it's threaded, the other form interactions are not part of the Button1 object/class -- they are written by the coder to the event that is raised when a user clicks.</p>