mixtape774
@mixtape774
Занимаюсь Web, Desktop разработкой и реверсингом

Как в C# реализовать изменение свойств нескольких компонентов в чужом потоке?

Доброго времени суток, друзья. Знаю что взаимодействовать с компонентами формы можно только через основной поток, поэтому для обращения к одному компоненту использовал такой код, вызывая через делегат:

private void AddTag(string tag)
        {
            if (tagList.InvokeRequired)
                tagList.Invoke(AddTagDelegate, tag);
            else
                tagList.Items.Add(tag);
        }


Но как быть в случае с несколькими компонентами? 10 раз писать *.Invoke(new ..., ...) ? Сомнительная идея.
Например с таким методом (вызывается из отдельного, только одного, потока).

public void BlockUI(bool onStart)
        {
                StartBtn.Enabled = threadsNumUpDown.Enabled = !onStart;
                StopBtn.Enabled = AbortBtn.Enabled = onStart;
        }

Были попытки использовать lock на заранее созданный Object, но безуспешно.
Многопоточность только осваиваю, поэтому не расстреливайте за подобные вопросы)
---
Буду признателен за любые полезные ответы. Заранее благодарен.
  • Вопрос задан
  • 4832 просмотра
Решения вопроса 1
aush
@aush
Я не уверен, что правильно понял ваш вопрос, но попробую предположить, что вы считаете, что Invoke должен вызываться у того контрола, действия с которым вы хотите совершить. Это не так - вы можете вызвать Invoke на любом контроле, который работает в том UI-потоке, контролы в котором вы хотите изменить.

Т.е. вы можете делать так:

private void AddTag(bool onstart)
{
    if (tagList.InvokeRequired)
        tagList.Invoke(new Action(() => BlockUI(onstart)));
    else
        BlockUI(onstart);
}


Вместо tagList может быть любой контрол, работающий в этом UI-потоке. Например, пусть у вас на форме три кнопки:

private void button1_Click(object sender, System.EventArgs e)
{
	var t = new Thread(new ThreadStart(() =>
	{
		if (button3.InvokeRequired)
		{
			button3.Invoke(new Action(() =>
			{
				button1.Text = "new button1 name";
				button2.Text = "new button2 name";
				button3.Text = "new button3 name";
			}));
		}
		else
		{
			button1.Text = "new button1 name";
			button2.Text = "new button2 name";
			button3.Text = "new button3 name";
		}                
	}));
	t.Start();
}


Кстати, форма тоже является контролом, так что в этом примере можно писать и так:

private void button1_Click(object sender, System.EventArgs e)
{
	var t = new Thread(new ThreadStart(() =>
	{
		if (InvokeRequired)
		{
			Invoke(new Action(() =>
			{
				button1.Text = "new button1 name";
				button2.Text = "new button2 name";
				button3.Text = "new button3 name";
			}));
		}
		else
		{
			button1.Text = "new button1 name";
			button2.Text = "new button2 name";
			button3.Text = "new button3 name";
		}                
	}));
	t.Start();
}
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
bstdman
@bstdman
Desktop разработчик
Почему бы не использовать класс Dispatcher?

Для окна:
YourWindow.Dispatcher.Invoke(() => {tagList.Items.Add(tag);});
Ответ написан
newross
@newross
Product owner
На самом деле все проще, надо использовать genereic метод. Пример www.codeproject.com/Articles/37413/A-Generic-Metho...
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы