0 / 0 / 0
Регистрация: 13.02.2009
Сообщений: 3
1

Обращение к элементу WinForms из потока, отличного от потока, в котором это элемент был создан

28.03.2010, 18:31. Показов 13796. Ответов 3
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Пишу приложение, котором при загрузке формы в textbox на этой форме заносятся данные. Причем данных много и процесс занимает длительное время. Чтобы при запуске у пользователя не возникало ощущения, что форма "подвисла" сделал заполнение textbox в отдельном потоке. Реализовал через асинхронный делегат, в упрощенном виде можно представить программу так:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Diagnostics;
 
namespace WindowsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        void TakesAWhile(int ms)
        {
            textBox1.AppendText("filling started");
            Thread.Sleep(ms);   //заполняем некоторое время
            textBox1.AppendText("filling completed");
            return;
        }
 
        public delegate void TakesAWhileDelegate(int ms);
 
 
        private void Form1_Load(object sender, EventArgs e)
        {
            TakesAWhileDelegate d1 = TakesAWhile;
            d1.BeginInvoke(3000, null, null);   //запустили поток заполнения textbox
            //дальше какие-то действия
        }
    }
}
В процессе выполнения компилятор ругнулся, что обращение к элементу textbox произошло из потока, отличного от потока, в котором это элемент был создан.
Почитал на MSDN про потокобезопасные вызовы, однако оба предложенных там потокобезопасных способа приводят к выполнению функции TakesAWhile в главном потоке и соответственно "подвисанию" формы.
Пришлось отключить сообщение об ошибке с помощью
Код
Control.CheckForIllegalCrossThreadCalls = false
в конструкторе формы.

Вопросы на повестке дня:
1)Насколько "хорошо" использование данного решения?
2)Есть ли другие потокобезопасные способы без "подвисания" формы (догадываюсь, что нет, т.к. textbox создан в главном потоке, но вдруг)?
3)Созданный BeginEnvoke дополнительный поток завершится после выполнения функции TakesAWhile или как?
И для чего тогда нужен метод EndEnvoke?

Заранее огромное спасибо.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
28.03.2010, 18:31
Ответы с готовыми решениями:

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

Попытка доступа к элементу не из того потока, в котором он был создан
Имею такой код: string strRegex8 = @"Проведено боёв: </td>\s*<*tdclass=""td-number"">...

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

Ошибка доступ к элементу ProgressBar не из того потока, в котором он был создан
Здравствуйте друзья. Cross-thread operation not valid: Control 'progressBar1' accessed from a...

3
1322 / 995 / 127
Регистрация: 08.12.2009
Сообщений: 1,299
29.03.2010, 16:35 2
1) плохо. надо хотя бы так
C#
1
2
3
4
5
6
7
8
9
        private void SetTextSafe(string text) {
            Action chTxt = new Action(() => {
                this.Text = text;
            });
 
            if (InvokeRequired)
                this.BeginInvoke(chTxt);
            else chTxt();
        }
- это потокобезопасный метод. можно вызывать откуда угодно

2) явно подвисать сможет если мой BeginInvoke изменить на Invoke, а в теле chTxt поставить что-то типа Thread.Sleep(1000);

3) да, завершится. EndEnvoke - это дань моде асинхронной модели программирования .NET . вызвав этот метод по завершении отработки делегата контекст этого созданного потока уходит в контекст синхронизации потока вызова, а, следовательно, можно к примеру получить результат выполнения асинхронного метода, его состояние, или отловить закэшированное в том потоке исключение. (разрушенный стек и пр.)

Добавлено через 4 минуты
или так:
C#
1
2
3
4
5
6
7
8
9
10
11
        private void SetTextSafe(string text) {
            if (InvokeRequired)
                this.BeginInvoke(new Action<string>((s) => {
                    SetText(s);
                }), text);
            else SetText(text);
        }
 
        private void SetText(string text) {
            this.Text = text;
        }
0
1923 / 428 / 41
Регистрация: 12.07.2007
Сообщений: 2,062
29.03.2010, 17:30 3
bairog, используйте контрол BackgroundWorker. В нем уже все реализовано.
Подписываетесь на события: DoWork - длительный рабочий код, ProgressChanged - изменяем форму в соответсвии с процентом выполнения рабочего кода, RunWorkerCompleted - процесс закончен.
0
5 / 5 / 0
Регистрация: 01.02.2010
Сообщений: 98
29.03.2010, 19:45 4
В GUI приложениях EndEnvoke не обязатателен. Лично я считаю, что лучше использовать отдельный поток (Thread) для длительных вычислений и выводить на форму по примеру Mikant. BackgroundWorker хорош, когда нужно вычислить что-либо в отдельном потоке и вывести это что-то в форму когда RunWorkerCompleted, более того, при старте BW возможно передать только один объект (при старте потока с использованием Thread можно передать несколько объектов). По поводу ProgressChanged - если честно то я так и не разобрался как, например, с его использованием производитьманипуляции с элементами формы, например , выводить текстовую информацию ... возможно он используется только для таких целей :-):
progressBar.Value = e.ProgressPercentage;
0
29.03.2010, 19:45
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
29.03.2010, 19:45
Помогаю со студенческими работами здесь

Попытка доступа к элементу управления 'label2' не из того потока, в котором он был создан
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data;...

Попытка доступа к элементу управления Label1 не из того потока в котором он был создан
Здравствуйте, у меня проблема, дело в том что при запуске генераций клеток выдает подобное...

Com port попытка доступа к элементу управления не из того потока, в котором он был создан
попытка доступа к элементу управления 'label2' не из того потока, в котором он был создан....

Непонятки с потоками (попытка доступа к элементу управления не из того потока, в котором он был создан)
Здравствуйте коллеги. Подскажите пожалуйста, как реализовать вывод на форму информации...

BackgroundWorker. Как получить доступ к элементу управления не из того потока, в котором он был создан
Пробую разместить парсер - ссылка в BackgroundWorker. Результат парсинга должен попадать из...

Многопоточность. Попытка доступа к элементу управления 'listBox1' не из того потока, в котором он был создан
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data;...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru