Передача аргументов между потоками с использованием делегатов - C#

Узнай цену своей работы

Формулировка задачи:

Правильно ли я понимаю что делегат будет вызван в том потоке в котором я его создал, а не в том в котором я его вызываю? У меня проблем с передачей данных между потоками с использованием делегатов. Мне нужно вызвать метод из созданного мною потока "DirtyJob" в основном потоке. Пытался это реализовать используя делегаты. В чем ошибка? Помогите исправить Logo.cs:
...
        internal DirtyJob MyDirtyJob = new DirtyJob();
        
        // #1 Создал делегат в основном потоке:
        public Logo()
        {
            InitializeComponent();
            MyDirtyJob.UpdateProgress += new UpdateProgressEvent(DirtyJob_UpdateProgress);
        }
        // Обновление информации на диалоговом окне
        private void DirtyJob_UpdateProgress(ProgressEventArgs e)
        {
            // #4 Тут происходит исключение
            // Cross-thread operation not valid: Control 'LabelProgressMessage' accessed from a thread other than the thread it was created on.
            // При этом в "Потоки" почему то указан не основной поток в качестве потока в котором сработала точка останова(исключение), а поток "DirtyJob"
            LabelProgressMessage.Text = e.Message;
        }
 
        private void Logo_Load(object sender, EventArgs e)
        {
            MyDirtyJob.StartJob();
        }
...
DirtyJob.cs:
...
    // Класс для передачи аргументов между потоками
    public class ProgressEventArgs
    {
        public ProgressEventArgs(int Progress, string Message)
        {
            _Progress = Progress;
            _Message = Message;
        }
        private volatile int _Progress;
        private volatile string _Message;
        public int Progress
        {
            get
            {
                return _Progress;
            }
        }
        public string Message
        {
            get
            {
                return _Message;
            }
        }
    }
    public delegate void UpdateProgressEvent(ProgressEventArgs e);
    public class DirtyJob
    {
        public event UpdateProgressEvent UpdateProgress;
        public void StartJob()
        {
            // Это работает!
            UpdateProgress(new ProgressEventArgs(0, "Запуск"));
            // #2 Создал и запустил новый поток: 
            Thread DirtyJobThread = new Thread(DoWork);
            DirtyJobThread.Name = "DirtyJob";
            DirtyJobThread.Start(this);
        }
        private void DoWork(object sender)
        {
            DirtyJob WorkThread = (DirtyJob)sender;
 
            // #3 Это приводит к исключению
            UpdateProgress(new ProgressEventArgs(1, "Проверка обновлений"));
        }
    }
...
п.с. Используя BackgroundWorker все прекрасно работает, но он мне не подходит и нужно обойтись без него!
Решил проблему завернув тело функции DirtyJob_UpdateProgress в BeginInvoke, но что мне делать когда объект метод которого я хочу вызвать не будет иметь никакого отношения к System.Windows.Forms?
        private void DirtyJob_UpdateProgress(ProgressEventArgs e)
        {
            BeginInvoke(new Action(() =>
                {
                    ShowButtonTimer.Stop();
                    ShowButtonTimer.Start();
                    CommonProgressBar.Value = e.Progress;
                    LabelProgressMessage.Text = e.Message;
                }));
        }

Решение задачи: «Передача аргументов между потоками с использованием делегатов»

textual
Листинг программы
using System;
using System.Windows.Forms;
 
namespace WindowsFormsProgressReporting
{
    public partial class Form1 : Form
    {
        DirtyJob MyDirtyJob;
 
        public Form1()
        {
            InitializeComponent();
 
            // вариант 1
            //Progress<ProgressEventArgs> progress = new Progress<ProgressEventArgs>(DirtyJob_UpdateProgress);
            //MyDirtyJob = new DirtyJob(progress);
 
            // вариант 2
            //MyDirtyJob = new DirtyJob(DirtyJob_UpdateProgress);
 
            // вариант 3
            MyDirtyJob = new DirtyJob();
            MyDirtyJob.Progress.ProgressChanged += Progress_ProgressChanged;
        }
 
        private void Progress_ProgressChanged(object sender, ProgressEventArgs e)
        {
            label1.Text = e.Message;
        }
 
        private void DirtyJob_UpdateProgress(ProgressEventArgs e)
        {
            label1.Text = e.Message;
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
            MyDirtyJob.StartJob();
        }
    }
}

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

5   голосов , оценка 3.8 из 5