Для операций в фоне советую использовать асинхронные операции. Если это сеть, то, например BeginSend и BeginWrite. В колбэках прописываем реакцию в GUI. Для того, чтобы операция выполнилась в GUI-потоке используем SynchronizationContext. Вот такой простой пример:
public partial class SimpleForm : Form
{
private readonly SynchronizationContext _context;
private readonly TcpListener _serverListener;
private int _connectionsCount;
public SimpleForm()
{
InitializeComponent();
// Зафиксировали GUI-поток
_context = SynchronizationContext.Current;
// Включаем ожидание входящих соединений
_serverListener = new TcpListener(IPAddress.Loopback, 30000);
_serverListener.Start();
_serverListener.BeginAcceptTcpClient(AcceptCallback, null);
}
private void AcceptCallback(IAsyncResult ar)
{
// Поймали соединение. Завершаем.
var client = _serverListener.EndAcceptTcpClient(ar);
// Сообщаем о новом подключении.
AddConnection();
}
private void AddConnection()
{
// Увеличиваем счетчик подключений
Interlocked.Add(ref _connectionsCount, 1);
// Сообщаем лейблу на форме новое значение. Используем GUI-поток, ибо в Callback'е находимся в чужом потоке из пула.
_context.Post(state => { lbConnCount.Text = _connectionsCount.ToString(); }, null);
}
}