Форум программистов, компьютерный форум, киберфорум
C# Windows Forms
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.69/13: Рейтинг темы: голосов - 13, средняя оценка - 4.69
6 / 6 / 1
Регистрация: 12.10.2016
Сообщений: 141
1

Backgroundworker ошибка

23.05.2019, 16:45. Показов 2483. Ответов 20
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Здравствуйте, решил по разбираться с потоками в winform, но получаю такую ошибку "System.InvalidOperationException: "Недопустимая операция в нескольких потоках: попытка доступа к элементу управления 'label1' не из того потока, в котором он был создан." В интернете как таковых примеров не нашел простых с использованием "backgroundworker". Как можно решить эту ошибку?

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
 
namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        BackgroundWorker worker;
        static int n = 0;
 
        public Form1()
        {
            InitializeComponent();
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            label1.Text = "";
            Thread thread = new Thread(new ThreadStart(SetTextLabel));
            thread.Start();
        }
 
        private void button2_Click(object sender, EventArgs e)
        {
            label2.Text = "";
 
            worker = new BackgroundWorker();
            worker.DoWork += (obj, ea) => SetTextLabel();
            worker.RunWorkerAsync();
        }
 
        public void SetTextLabel()
        {
            Thread.Sleep(1000);
            label1.Text = n.ToString();
            n++;
 
            Thread.Sleep(1000);
            label2.Text = n.ToString();
            n++;
        }
    }
}
Миниатюры
Backgroundworker ошибка   Backgroundworker ошибка  
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
23.05.2019, 16:45
Ответы с готовыми решениями:

BackgroundWorker и MainForm ошибка потока
Уважаемые участники форума. Помогите пожалуйста. Пишу программу и никак не могу победить...

Сканирование адресов в backgroundworker. Ошибка "Сервер RPC недоступен"
Всем привет. Извините если не так оформил название темы. Написал код, который сканирует диапозон...

BackgroundWorker
Уважаемые пользователи! Подскажите, пожалуйста, следующее: Есть программа, в которой протекают...

BackgroundWorker
Есть 10 button-ов и 1 backgroundWorker. При нажатии на любой button должен запускаться поток, в...

20
Эксперт .NET
6507 / 4084 / 1605
Регистрация: 09.05.2015
Сообщений: 9,548
23.05.2019, 16:47 2
Обновлять Label при использовании BackgroundWorker нужно из события ProgressChanged.
Для обычного потока Thread придется городить Invoke.

BackgroundWorker Class
1
6 / 6 / 1
Регистрация: 12.10.2016
Сообщений: 141
24.05.2019, 18:40  [ТС] 3
Спасибо за ссылку, очень помогла. На самом деле BackgroundWorker я использую в файловом менеджере при работе с левым и правым окнами. Когда открываю папку system32 в каком то окне, у меня зависает вся программа, до тех пор пока не заполнится listview. Так и должно быть? или надо использовать сам Thread?
0
Эксперт .NET
11068 / 6985 / 1571
Регистрация: 25.05.2015
Сообщений: 21,063
Записей в блоге: 14
24.05.2019, 18:48 4
Yerta, данные считывайте в потоке, но заполняйте ListView только по получении уже всех данных, т.е. по завершении.
0
6 / 6 / 1
Регистрация: 12.10.2016
Сообщений: 141
25.05.2019, 13:21  [ТС] 5
Скорее всего так не получится. Метод в котором заполняю ListView, без него не получится, так как "lvl = lv.Items.Add(dirname, 9);" - добавляю строку, а "lvl.SubItems.Add(File.GetCreationTime(item).ToString());" - вставляет данные. Я создавал динамический ListView, что бы заполнить ним после окончания этого метода так сказать физический лист, но получал ошибку и-за того что данные типа используются в двух листах. Как вы говорили "данные считывайте в потоке, но заполняйте ListView только по получении уже всех данных, т.е. по завершении." я не знаю как это сделать.

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
public void GetFileS()
        {
            Cursor = Cursors.WaitCursor;
            List<string> slOld = new List<string>();
            if (ii == 0) { slOld = sl; } else { slOld = sl2; }   
 
            lv.BeginUpdate(); // ListView
            try
            {
                slOld.Clear();              
                lv.Items.Clear();
 
                lv.Columns[3].Text = "Дата";
                lv.Columns[4].Text = "Атрибут";
 
                foreach (var item in Directory.GetDirectories(Fpath))
                {
                    string dirname = Path.GetFileName(item);
                    try
                    {
                        if ((File.GetAttributes(item.ToString()) & FileAttributes.Hidden) == FileAttributes.Hidden)
                        {
                            lvl = lv.Items.Add(dirname, 9);
                        }
                        else {
                            lvl = lv.Items.Add(dirname, 6);
                        }
                    }
                    catch (UnauthorizedAccessException)
                    {
                        lvl = lv.Items.Add(dirname, 8);
                    }
 
                    lvl.SubItems.AddRange(new string[] { string.Empty, "Папка с файлами" });                    
                    lvl.SubItems.Add(File.GetCreationTime(item).ToString());                   
 
                    if ((File.GetAttributes(item) & FileAttributes.Hidden) == FileAttributes.Hidden)
                    {
                        lvl.SubItems.Add("h");
                    }
                    else
                    {
                        lvl.SubItems.Add("a");
                    }
                 
                    slOld.Add(item);
                }
 
                //FileInfo[] fi = new DirectoryInfo(Fpath).GetFiles();
 
                //foreach (var item in Directory.GetFiles(Fpath))
                //{
                //    string filename = Path.GetFileNameWithoutExtension(item);
                //    imageList1.Images.Add(Icon.ExtractAssociatedIcon(item));
                //    if ((File.GetAttributes(item) & FileAttributes.System) != FileAttributes.System)
                //    {
                //        //lvl = lv.Items.Add(filename, imageList1.Images.Count - 1);
                //        lvl = lv.Items.Add(filename, imageList1.Images.Count - 1);
                //        //lvl.SubItems.Add(Path.GetExtension(item));
                //        //lvl.SubItems.Add(Convert.ToString(fi[count].Length / 1024 + " КБ"));
                //    }
                //    //lv.Columns[3].Text = "Дата";
                //    //lvl.SubItems.Add(File.GetCreationTime(item).ToString());
                //    //lv.Columns[4].Text = "Атрибут";
                //    //if ((File.GetAttributes(item) & FileAttributes.Hidden) == FileAttributes.Hidden)
                //    //{
                //    //    lvl.SubItems.Add("h");
                //    //}
                //    //else
                //    //{
                //    //    lvl.SubItems.Add("a");
                //    //}
                //}
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Внимание", MessageBoxButtons.OK, MessageBoxIcon.Stop);
            }
            lv.EndUpdate();
            Cursor = Cursors.Default;            
        }
 
private void listView2_ItemActivate(object sender, EventArgs e)
        {
            if (!backgroundWorker1.IsBusy)
            {
                backgroundWorker1.RunWorkerAsync();
            }
        }
 
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            backgroundWorker1.ReportProgress(0);
        }
 
        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            //Cursor = Cursors.WaitCursor;
            ii = 1;
            lv = listView2;
            ItemActivate(sl2);                     // метод вызывающий GetFiles();
            //Cursor = Cursors.Default;
        }
 
        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
          // здесь должен был просто заполнить лист результатами метода GetFiles();
        }
0
Эксперт .NET
11068 / 6985 / 1571
Регистрация: 25.05.2015
Сообщений: 21,063
Записей в блоге: 14
25.05.2019, 13:26 6
Вы файлы и каталоги считываете? Под читайте их в потоке и собирайте только необходимые данные. Не в ListView.
К визуальному контролу обращайтесь только тогда, когда все данные будут собраны.
0
6 / 6 / 1
Регистрация: 12.10.2016
Сообщений: 141
25.05.2019, 13:43  [ТС] 7
Да, считывание происходит моментально. Не совсем вас понял, данные я собрал в массивы допустим, мне потом этими данными нужно заполнить ListView. В любом случаи произойдем зависание формы, без разницы где я считываю эти данные в потоке или нет.
Где собрать данные? это не понял
0
6 / 6 / 1
Регистрация: 12.10.2016
Сообщений: 141
25.05.2019, 14:15  [ТС] 8
Такое у меня происходит даже в этой программе, которую делал по примеру. Когда запуская поток кнопкой1, я не могу нажать кнопку2, так как приложение зависает
Вложения
Тип файла: 7z WindowsFormsApp1 — копия.7z (160.2 Кб, 2 просмотров)
0
Эксперт .NET
6507 / 4084 / 1605
Регистрация: 09.05.2015
Сообщений: 9,548
25.05.2019, 14:28 9
Цитата Сообщение от Yerta Посмотреть сообщение
В любом случаи произойдем зависание формы, без разницы где я считываю эти данные в потоке или нет.
У меня ничего не зависает.
Вложения
Тип файла: zip WindowsFormsApp2.zip (11.6 Кб, 4 просмотров)
0
Эксперт .NET
6507 / 4084 / 1605
Регистрация: 09.05.2015
Сообщений: 9,548
25.05.2019, 14:45 10
Цитата Сообщение от Yerta Посмотреть сообщение
Такое у меня происходит даже в этой программе, которую делал по примеру. Когда запуская поток кнопкой1, я не могу нажать кнопку2, так как приложение зависает
Потому что вы всё неправильно сделали.
Вложения
Тип файла: zip WindowsFormsApp1 — копия.zip (12.3 Кб, 7 просмотров)
1
Эксперт .NET
11068 / 6985 / 1571
Регистрация: 25.05.2015
Сообщений: 21,063
Записей в блоге: 14
25.05.2019, 15:39 11
Цитата Сообщение от Yerta Посмотреть сообщение
Такое у меня происходит даже в этой программе, которую делал по примеру. Когда запуская поток кнопкой1, я не могу нажать кнопку2, так как приложение зависает
Все новички, игнорирующие учебную литературу и впервые столкнувшиеся с потоками, повторяют одну и ту же ошибку:
  • Есть длительная функция.
  • По событию кнопки оно вызывается и форма зависает. Потому что очередь сообщений окна остановлена выполнением длительной функции.
  • На форуме советуют применить потоки.
  • Вызываем эту функцию из потока. Вылетает ошибка о доступе к контролам GUI. Потому что к ним можно обращаться только из потока GUI, т.е. из очереди сообщений.
  • На форуме советуют один или несколько методов доступа к контролам из потока. Invoke, BeginInvoke, BackgroundWorker.ReportProgress, IReport<T>, TaskScheduler... Которые делегируют вызов указанной им функции в поток GUI, вставляя его в очередь сообщений.
  • Новичок принимает "гениальное" решение запихнуть всю свою длительную функцию в такой вызов. Это же так просто! Ничего не надо переделывать, тяп-ляп и готово!
  • Программа виснет, как прежде. Потому что вызов длительной функции снова производится из очереди сообщений, полностью останавливая её.
  • Далее минимум 2 варианта:
    • Новичок читает мануалы и раздумывает над тем, почему так, и познаёт дзен смысл очереди сообщений.
    • Ничего не изучая, ищет на форуме, как заставить GUI обновиться. Находит одну костыльную функцию для конкретной среды разработки и применяет её. Всё работает! Тяп-ляп и готово!
      Программа начинает себя вести неадекватно, да и вообще происходящее в ней не поддаётся никакой логике и превращается в лютый треш. Потому что логика очереди сообщений поломана.

Добавлено через 26 минут
Yerta,
Всё, что вызывается из очереди сообщений (клик по кнопке, например), должно выполняться мгновенно. Тогда окна не будут виснуть.
Всё долгое, больше 1-10 мс, надо выносить в потоки различного вида.
3
6 / 6 / 1
Регистрация: 12.10.2016
Сообщений: 141
25.05.2019, 17:32  [ТС] 12
В виртуальном режиме можно добавить иконку файла в элемент?
0
Эксперт .NET
11068 / 6985 / 1571
Регистрация: 25.05.2015
Сообщений: 21,063
Записей в блоге: 14
25.05.2019, 17:47 13
Почему вы решили перейти к виртуальному режиму?

Добавьте виртуальному итему ImageList и ImageIndex.
0
6 / 6 / 1
Регистрация: 12.10.2016
Сообщений: 141
25.05.2019, 17:56  [ТС] 14
Rius, он быстрее работает, читал у вас на форуме и на других сайтах. Да и с ним меньше заморочек при добавлении строк
0
Эксперт .NET
11068 / 6985 / 1571
Регистрация: 25.05.2015
Сообщений: 21,063
Записей в блоге: 14
25.05.2019, 17:58 15
Да, быстрее. Только пока вы тот способ не освоили, это будет что мёртвому припарка.
0
6 / 6 / 1
Регистрация: 12.10.2016
Сообщений: 141
25.05.2019, 18:10  [ТС] 16
Rius, освоил, проблема с зависание формы решена, но все равно должно заполняет мой ListView. Поэтому решил все переделать под Virtual Mode
0
6 / 6 / 1
Регистрация: 12.10.2016
Сообщений: 141
26.05.2019, 17:14  [ТС] 17
Вопрос по поводу строки 19, если не использовать Invoke, то у меня происходит зависание 2-х ListView, не самой формы, можете сказать причину? ImageList у меня 2, для каждого ListView
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
public void GetFileS(string Path, ImageList imagelist)
        {
            List<Data> datas = new List<Data>();
            if (ii == 0) { datas = datas1; } else { datas = datas2; }
            try
            {
                datas.Clear();
 
                foreach (var dir in new DirectoryInfo(Path).EnumerateDirectories())
                {
                    datas.Add(new Data() { ImageIndex = 6, Name = dir.Name, Type = "Directory", Date = dir.CreationTime, Attributes = dir.Attributes, FullPath = dir.FullName });
                }
 
                foreach (var file in new DirectoryInfo(Path).EnumerateFiles())
                {
                    Data data = new Data();
 
                    this.Invoke((MethodInvoker)(() => imagelist.Images.Add(Icon.ExtractAssociatedIcon(file.FullName))));
                    this.Invoke((MethodInvoker)(() => data.ImageIndex = imagelist.Images.Count - 1));
 
                    data.Name = file.Name;
                    data.Type = file.Extension;
                    data.Size = file.Length.ToString();
                    data.Date = file.CreationTime;
                    data.Attributes = file.Attributes;
                    datas.Add(data);                  
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Внимание", MessageBoxButtons.OK, MessageBoxIcon.Stop);
            }
        }
0
Эксперт .NET
6507 / 4084 / 1605
Регистрация: 09.05.2015
Сообщений: 9,548
26.05.2019, 17:43 18
Думаю начинать стоит с того, зачем вам там Invoke и почему не сделать по другому? Всегда можно написать так, чтобы никаких Invoke не требовалось... Например сделать отдельный список для иконок, а не сразу пихать их в ImageList... Можно даже список не делать, а сохранять иконку в тот же класс Data...
1
Эксперт .NET
11068 / 6985 / 1571
Регистрация: 25.05.2015
Сообщений: 21,063
Записей в блоге: 14
26.05.2019, 18:08 19
Ну и ещё: нафига пихать каждую иконку в список, если их количество гораздо меньше количества файлов?..
1
6 / 6 / 1
Регистрация: 12.10.2016
Сообщений: 141
26.05.2019, 21:40  [ТС] 20
Invoke использовал для устранения ошибки, как то сразу не додумался это сделать списком, спасибо
0
26.05.2019, 21:40
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
26.05.2019, 21:40
Помогаю со студенческими работами здесь

BackgroundWorker
Приветствую . Пытаюсь закодить проект с динамическим добавлением потоков , все бы хорошо , но я не...

BackgroundWorker
Можно ли определить ProgressChanged для всех BackgroundWorker`ов? Или как осуществить подобное?

BackgroundWorker и SaveFileDialog
Добрый вечер! Не работает сохранение текстового файла с помощью SaveFileDialog и прикрученным к...

BackgroundWorker.RunWorkerCompleted
RunWorkerCompletedEventArgs в событии RunWorkerCompleted содержит e.Error типа Exception. Как в...


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

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