Quando si lavora con i threads in applicazioni Windows vige la regola (col framework 2.0 divenuta finalmente ferrea) di non accedere ad un controllo Windows da threads diversi da quelli che lo hanno creato.
Ho gia' indicato come deve avvenire il tutto con il framework 1.0 e ho da poco scoperto che nel framework 2.0
esiste una classe WindowsFormsSyncronizationContext fatta ad-hoc per questo scopo.
Questa classe, che viene automaticamente valorizzata non appena si invoca Application.Run, si occupa di
recuperare automaticamente il controllo sul quale chiamare il metodo Invoke passandogli un SendOrPostCallback delegate.
Ad esempio, per incrementare una progressbar da un thread secondario possiamo scrivere (anche grazie agli
anonymous methods di C# 2.0):

using System.Threading; 
private void button1_Click(object sender, EventArgs e)
{
  Thread t = new Thread(DoWork);
  t.Start(WindowsFormsSynchronizationContext.Current);
}

void DoWork(object o)
 {
  WindowsFormsSynchronizationContext context = (WindowsFormsSynchronizationContext) o;
  for (int i = 0; i < 100; i++)
  {
   context.Send(delegate(object v) { progressBar1.Value = i; }, null);
  }
 }

In VB2005 il codice e' leggermente diverso:

Imports System.Threading

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
  Dim t As New Thread(AddressOf DoWork)
  t.Start(WindowsFormsSynchronizationContext.Current)
End Sub

Public Sub DoWork(ByVal o As Object)
  Dim context As WindowsFormsSynchronizationContext = DirectCast(o, WindowsFormsSynchronizationContext)
  For i As Integer = 0 To 100
   context.Send(New SendOrPostCallback(AddressOf UpdateUI), i)
  Next
End Sub

Private Sub UpdateUI(ByVal o As Object)
 ProgressBar1.Value = Convert.ToInt32(o)
End Sub

Questa classe rende ancora piu' semplice la creazione di componenti che internamente utilizzano threads ma generano eventi senza richiedere marshaling, come fa ad esempio la classe BackgroundWorker.
Esempio:

using System.Threading;
using System.Windows.Forms;

 public class SafeEvents
 {
  SynchronizationContext mContext;
  public event EventHandler<ProgressArgs>  MyEvent;

  public SafeEvents() {mContext = WindowsFormsSynchronizationContext.Current;}

  public void Run()
  {
   Thread t = new Thread(delegate()
   {
    for (int i = 0; i < 100; i++)
    {
     if (MyEvent != null)
      mContext.Send(delegate(object o){MyEvent(this, new

ProgressArgs(i));},null);
   
    }
   });
   t.Start();
  }
 }
 
 public class ProgressArgs:EventArgs
 {     
  public ProgressArgs (int value){this.value=value;}
  private int value;
  public int Value{get { return value;}}
 }

Che posso usare direttamente in questo modo:

SafeEvents evn = new SafeEvents();
evn.MyEvent+= MyEvent;
evn.Run();

void MyEvent(object sender, ProgressArgs e)
{
  progressBar1.Value = e.Value;
}