Задать вопрос

Как привязать ProgressBar в C# (Windows Forms) к определенному методу?

Доброго времени суток!
Пишу WinForms-приложение на C#. Это solution из нескольких проектов. В одном проекте собрана, так сказать, изобразительная часть, а основные действия выполняются в другом. В первом проекте есть форма с кнопкой запуска долгоиграющего процесса из второго проекта. Возможно ли каким-либо образом привязать ProgressBar на форме в первом проекте к выполнению этого долгоиграющего процесса из второго?

Вот так примерно выглядит структура solution-а.

Первый проект - там сама форма.

using Project2;

namespace Project1
{
public partial class frmRun : Form
{
LongRunningTaskPerformer _ltp;
//...
private void btnRun_Click(object sender, EventArgs e)
{
_ltp = new LongRunningTask();
_ltp.Run();
}
}
}

Второй проект - там долгоиграющий процесс, к которому необходимо привязать ProgressBar.

namespace Project2
{
public class LongRunningTaskPerformer
{
//...
public void Run()
{
DoStep1();
DoStep2();
DoStep3();
}

private void DoStep1()
{
Thread.Sleep(10000);//здесь может быть еще что-нибудь
}

private void DoStep2()
{
Thread.Sleep(10000);//здесь может быть еще что-нибудь
}

private void DoStep3()
{
Thread.Sleep(10000);//здесь может быть еще что-нибудь
}
}
}
  • Вопрос задан
  • 7720 просмотров
Подписаться 4 Оценить Комментировать
Решения вопроса 1
aush
@aush
При создании LongRunningTaskPerformer-а передавать ему зависимость на нечто вроде
public interface INotifyProgress
{
  void Notify(int percent);
}

и в форме frmRun реализовать INotifyProgress (не забывайте делать проверку на необходимость Invoke при работе с UI из реализации Notify(). Соответственно, LongRunningTaskPerformer сможет сообщать о своем состоянии, а frmRun будет реагировать на это изменение путем отображения прогресс-бара.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@skosterin88 Автор вопроса
aush, спасибо! Заработало.
Для тех, кому актуально - привожу код:

DLL-ка с долгоиграющим процессом (LongRunningTask):

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;//чисто для задержки потоков, т.е. для симуляции долгоиграющего процесса

namespace LongRunningTask
{
    public class LongRunningTaskPerformer
    {
        //Интерфейс оповещения, реализуемый клиентом, которому интересно состояние долгоиграющего процесса.
        //В нашем случае это форма запуска.
        private readonly INotifyProgress _notifier;

        public LongRunningTaskPerformer(INotifyProgress notifier)
        {
            if (notifier != null)
            {
                _notifier = notifier;
            }
        }

        public void Run()
        {
            //После каждого шага вызываем метод-оповещатель Notify. В случае с формой в реализации этого метода будет обновление прогресс-бара.
            DoStep1();
            _notifier.Notify(33);
            DoStep2();
            _notifier.Notify(66);
            DoStep3();
            _notifier.Notify(100);
        }

        private void DoStep1()
        {
            Debug.WriteLine("Step 1");
            Thread.Sleep(12000);
            Debug.WriteLine("Step 1 completed!");
        }

        private void DoStep2()
        {
            Debug.WriteLine("Step 2");
            Thread.Sleep(12000);
            Debug.WriteLine("Step 2 completed!");
        }

        private void DoStep3()
        {
            Debug.WriteLine("Step 3");
            Thread.Sleep(12000);
            Debug.WriteLine("Step 3 completed! Work done.");
        }
    }
}


В рамках этой DLL-ки - интерфейс-оповещатель INotifyProgress:

namespace LongRunningTask
{
    public interface INotifyProgress
    {
        void Notify(int percent);
    }
}


А вот основной проект, в котором содержится форма запуска, использующая BackgroundWorker при обновлении прогресс-бара (MyProgressBar):

namespace MyProgressBar
{
    //Наша форма запуска реализует интерфейс оповещения INotifyProgress. Это надо, чтобы форма смогла получать данные о состоянии долгоиграющего процесса
    //ПО МЕРЕ его выполнения. Без реализации интерфейса ничего работать не будет!
    public partial class frmProgressBar : Form, INotifyProgress
    {
        //Класс, выполняющий наш долгоиграющий процесс
        LongRunningTaskPerformer _ltp;
        //Делегат, воспроизводящий внешний вид метода-оповещателя из интерфейса INotifyProgress.
        //Он нужен для обеспечения потокобезопасной передачи данных в форму. Если его не будет, программа вылетит
        //с исключением типа "обращение к progressBar не из его потока" (или что-то подобное).
        delegate void NotifyCallback(int value);

        public frmProgressBar()
        {
            InitializeComponent();
        }

        //Сам процесс запускается с помощью backgroundWorker-а. Кнопка Run только запускает этот backgroundWorker.
        private void btnRun_Click(object sender, EventArgs e)
        {
            backgroundWorker1.RunWorkerAsync();
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            //Выполнение долгоиграющего процесса. 
            _ltp = new LongRunningTaskPerformer(this);
            _ltp.Run();
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar1.Value = e.ProgressPercentage;
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            //Как-то показываем, что у нас завершился наш долгоиграющий процесс и возвращаем прогресс-бар в исходное состояние.
            MessageBox.Show("Process completed!");
            progressBar1.Value = 0;
        }

        //Реализация процедуры оповещения о состоянии долгоиграющего процесса.
        public void Notify(int percent)
        {
            //Чтобы передача состояния процесса сработала корректно и программа не вылетела, 
            //надо делать в точности как здесь (за подробностями - MSDN: 
            //http://msdn.microsoft.com/query/dev11.query?appId=Dev11IDEF1&l=EN-US&k=k%28EHInvalidOperation.WinForms.IllegalCrossThreadCall%29;k%28TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5%29;k%28DevLang-csharp%29&rd=true)

            if (progressBar1.InvokeRequired)
            {
                NotifyCallback d = new NotifyCallback(Notify);
                this.Invoke(d, new object[] { percent });
            }
            else
            {
                progressBar1.Value = percent;
            }
        }
    }
}
Ответ написан
Комментировать
Ваш ответ на вопрос

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

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