S
S
skosterin882014-11-03 23:15:16
C++ / C#
skosterin88, 2014-11-03 23:15:16

How to bind ProgressBar in C# (Windows Forms) to a specific method?

Good day!
I am writing a WinForms application in C#. This is a solution from several projects. In one project, the visual part is collected, so to speak, and the main actions are performed in another. The first project has a form with a button to launch a long-running process from the second project. Is it possible somehow to bind the ProgressBar on the form in the first project to the execution of this long-running process from the second one?
This is how the structure of the solution looks like.
The first project is the form itself.
using Project2;
namespace Project1
{
public partial class frmRun : Form
{
LongRunningTaskPerformer _ltp;
//...
private void btnRun_Click(object sender, EventArgs e)
{
_ltp = new LongRunningTask();
_ltp.Run();
}
}
}
The second project is a long-running process, to which you need to attach a ProgressBar.
namespace Project2
{
public class LongRunningTaskPerformer
{
//...
public void Run()
{
DoStep1();
DoStep2();
DoStep3();
}
private void DoStep1()
{
Thread.Sleep(10000);// there might be something else here
}
private void DoStep2()
{
Thread.Sleep(10000);//something else here
}
private void DoStep3()
{
Thread.Sleep(10000);//something else here
}
}
}

Answer the question

In order to leave comments, you need to log in

2 answer(s)
A
aush, 2014-11-04
@skosterin88

When creating a LongRunningTaskPerformer, pass it a dependency on something like

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

and implement INotifyProgress in the frmRun form (do not forget to check for the need for Invoke when working with the UI from the Notify() implementation. Accordingly, LongRunningTaskPerformer will be able to report its state, and frmRun will respond to this change by displaying a progress bar.

S
skosterin88, 2014-11-06
@skosterin88

ush , thanks! Earned.
For those who are interested, here is the code:
DLL with a long-running process (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.");
        }
    }
}

Within this DLL, there is an INotifyProgress notifier interface:
namespace LongRunningTask
{
    public interface INotifyProgress
    {
        void Notify(int percent);
    }
}

And here is the main project, which contains a start form that uses a BackgroundWorker when updating the progress bar (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;
            }
        }
    }
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question