Доступ к элементам из другого потока в C#

Как же получить доступ к элементам из другого потока в языке программирования C#? Просто! Через свойство InvokeRequired требуемого элемента узнаём требуется ли вызов из другого потока, и если требуется, через метод Invoke (синхронно) или BeginInvoke (асинхронно) требуемого элемента выполняем необходимые действия.

Методы Invoke и BeginInvoke принимают делегат (указывающий на функцию).
Свой собственный делегат можно не определять а воспользоваться стандартным делегатом, например, Action.
Определять отдельно выполняемый метод для делегата так же не обязательно, можно прописать анонимный метод.
Анонимный метод в C# создаётся либо при помощи ключевого слова delegate так:

delegate(/* параметры */) {/* код */},

либо при помощи лямбда-выражений так:

(/* параметры */) => { /* код */ }

У метода Invoke (или BeginInvoke) есть 1 перегрузка, ему первым параметром надо передать делегат указывающий на функцию, а вторым параметром можно передать массив аргументов для этой функции.

Пример 1. Используется стандартный делегат Action и анонимная функция созданная при помощи ключевого слова delegate:

if (progressBar1.InvokeRequired) {
	progressBar1.BeginInvoke(new Action(delegate() { progressBar1.Value = 0; }));
} else
	progressBar1.Value = 0;

Пример 2. Используется стандартный делегат Action и анонимная функция созданная при помощи лямбда-выражений:

if (listBox1.InvokeRequired)
	listBox1.BeginInvoke(new Action(() => { listBox1.Items.AddRange(arrRivers); }));
else
	listBox1.Items.AddRange(arrRivers);

Пример 3. Используется пользовательский делегат labelTextDelegate, созданный под метод LabelText. В методе LabelText в метод BeginInvoke первым параметром передаётся пользовательский делегат labelTextDelegate, который ссылается (выполняет) на метод LabelText и вторым параметром передаётся массив аргументов для функции на которую ссылается делегат из первого параметра. В массиве аргументов передаётся параметр text.

delegate void labelTextDelegate(string text);
string text;
if (InvokeRequired)
		BeginInvoke(new labelTextDelegate(LabelText), new object[] {text});
else
	label1.Text = text;
private void LabelText(string text) {}

Пример 4. Метод вызывает сам себя в нужном потоке. Используется пользовательский делегат labelTextDelegate созданный под метод LabelText. В методе LabelText в метод BeginInvoke первым параметром передаётся пользовательский делегат labelTextDelegate, который ссылается (выполняет) на метод LabelText и вторым параметром передаётся массив аргументов для функции на которую ссылается делегат из первого параметра. В массиве аргументов передаётся параметр text, который был передан методу LabelText. Таким образом метод LabelText потокобезопасен т.к. проверяет надо ли его выполнять в другом потоке, и если надо, то выполняет.

delegate void labelTextDelegate(string text);
private void LabelText(string text) {
	if (InvokeRequired)
			BeginInvoke(new labelTextDelegate(LabelText), new object[] {text});
	else
		label1.Text = text;
}

Пример 5. Почти всё тоже самое, что и в примере выше только в Invoke передаётся переменная-объект делегата.

delegate void AddStackItem(string item);
AddStackItem m_addToStackDelegate;
private void AddToStackPanel(string us) {
	m_addToStackDelegate = new AddStackItem(AddToStackPanel);
	if (stackPanel1.InvokeRequired) {
		//stackPanel1.BeginInvoke(new Action(() => { stackPanel1.Children.Add(us); })); //неверно
		stackPanel1.Invoke(m_addToStackDelegate, new object[] {us});
	}
	else
		stackPanel1.Children.Add(us);
}