Если поток выполняется где-то в бизнес-слое и не знает про форму, то можно использовать контекст синхронизации. Вот так:
При создании формы:
SynchronizationContext uiContext = SynchronizationContext.Current;
Thread thread = new Thread(Run);
// Запустим поток и установим ему контекст синхронизации,
// таким образом этот поток сможет обновлять UI
thread.Start(uiContext);
Код потока:
private void Run(object state)
{
// вытащим контекст синхронизации из state'а
SynchronizationContext uiContext = state as SynchronizationContext;
// говорим что в UI потоке нужно выполнить метод UpdateUI
// и передать ему в качестве аргумента строку
uiContext.Post(UpdateUI, "Hello world!");
}
И код который выполняет действие по изменению UI
/// <summary>
/// Этот метод исполняется в основном UI потоке
/// </summary>
private void UpdateUI(object state)
{
sampleListBox.Items.Add((string)state);
}
При этом никаких beginInvoke'ов в методе UpdateUI уже не потребуется, т.к. код однозначно исполняется в UI потоке.