До сих пор мы работали с консолью не просто так. Дело в том, что у потоков есть множество ограничений. Далеко не все объекты .NET также безопасно могут существовать при обращении к ним со стороны нескольких потоков. Давайте посмотрим это на примере. Создайте новое WinForms-приложение и поместите на форму компонент RichTextBox и кнопку. Пишем код, который должен выполняться по нажатию кнопки:
private void button1_Click(object sender, EventArgs e) { Thread thread = new Thread(new ThreadStart(ThreadFunction)); thread.Start(); }
Здесь у нас создается и запускается на выполнение новый поток, который будет выполнять метод ThreadFunction(). Метод потока выглядит следующим образом:
void ThreadFunction() { for (int i = 0; i < 10; i++) richTextBox1.AppendText(i.ToString()); }
Здесь мы в цикле из десяти шагов пытаемся вывести число в компонент RichTextBox. На самом деле у нас не выйдет даже одного раза вывести что-то в этот компонент. Нет, мы сможем откомпилировать пример и даже запустить его на выполнение. Но при попытке нажать на кнопку произойдет исключительная ситуация. На рис. 1 показано сообщение об исключительной ситуации из среды разра- ботки.
Рис. 1. Сообщение об исключительной ситуации
Нельзя обращаться к элементам управления, которые были созданы в других потоках. Наш элемент управления на форме был сделан в основном потоке, а доступ мы пытаемся получить из дочернего потока. Так как же нам получить доступ к компоненту из потока? Эта задача достаточно популярна при работе с потоками и решается довольно легко — через делегаты.
Для вывода текста в RichTextBox напишем следующий метод:
void PrintFunc(string str) { richTextBox1.AppendText(str); }
Метод выводит в компонент переданный в качестве параметра текст. Чтобы вызвать этот метод, нужно объявить соответствующий делегат и переменную делегата:
delegate void PrintInRhichTextBox(string str); private PrintInRhichTextBox PrintDelegateFunc;
В конструкторе инициализируем переменную делегата:
PrintDelegateFunc = new PrintInRhichTextBox(PrintFunc);
Теперь можно вызывать этот метод через делегат. Но не просто так, а через метод Invoke() компонента:
richTextBox1.Invoke(PrintDelegateFunc, new object[] { i.ToString() });
Методу Invoke() передаются два параметра:
В нашем случае методу делегата нужно передать только один параметр — строку, которая должна выводиться в компоненте, ее и передаем.
Метод Invoke() компонента вызывает указанный метод делегата в потоке, которому и принадлежит этот компонент. Метод Invoke() возвращает значение, которое возвращает вызываемый делегат, или null, если делегат не возвращает никаких значений.
Вот и все. Немного сложновато, но эффективно. При таком вызове делегата он будет работать в том потоке, в котором был создан компонент, а значит, исключительной ситуации не возникнет.
Внимание!!! Если ты копируешь эту статью себе на сайт, то оставляй ссылку непосредственно на эту страницу. Спасибо за понимание
Паника, что-то случилось!!! Ничего не найдено в комментариях. Срочно нужно что-то добавить, чтобы это место не оставалось пустым.
Добавить Комментарий