0

To make it simple, I have two projects:

  • project A : windows form application

  • project B : a C# class library project

B is referenced on A, so A can not be referenced on B. B got the main business of the whole program, and I need to display some information (feedbacks, warnings, errors ..) on the GUI (project A).

It is very annoying the sending back the information from the project B to the project A everytime to display it.

Any ideas?

R. Gadeev
  • 188
  • 3
  • 12
Mehdi Souregi
  • 3,153
  • 5
  • 36
  • 53
  • 1
    *It is very annoying the send back the information from the project B to the project A* Can you please explain by enclosing a [MCVE] to demonstrate this? Class in project B is doing what ? That is how common controls are held in a DLL and loaded in place dynamically on a GUI in another project. Maybe you are attempting that fashion? – t0mm13b May 11 '17 at 10:11
  • That's how it works. Normally you have 3 projects at least, 1: UILogic, 2: BusinessLogic, 3: Application and you send data from BusinessLogic to UILogic which is then displayed by Applications... – mrogal.ski May 11 '17 at 10:11
  • 1
    _It is very annoying the send back the information from the project B to the project A everytime to display it_ - this how UI and business logic works - check : [Windows Forms Data Binding](https://msdn.microsoft.com/en-us/library/ef2xyb33(v=vs.110).aspx) – Fabio May 11 '17 at 10:12
  • i have huge methods inside the business, and i need to display some information on the GUI while the business method is not finished yet the processing – Mehdi Souregi May 11 '17 at 10:14
  • 2
    Then you should re-design your methods - if not, you end up with huge mess. And your current problem is a sign for you about it – Fabio May 11 '17 at 10:15
  • Sounds like a readup on threading using `async` and `await` tasks is required for you in order to do this for you, process info on the data, with a callback to the UI, using thread safe marshalling so not to create cross-thread exceptions. – t0mm13b May 11 '17 at 10:17

2 Answers2

4

The class library should notify the UI project of a change that it can react to and draw the correct UI.

There are a number of aproaches from a method that the UI layer passes to the project B (callbacks) to events the UI layer can subscribe to.

Below is an example with events. See here for more details on raising custom events.

  public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            var projectB = new ProjectB();
            projectB.OnUpdateStatus += projectB_OnUpdateStatus;
            projectB.Run();
        }

        private void projectB_OnUpdateStatus(string message)
        {
            MessageBox.Show(message);
        }
    }



public class ProjectB
{
    public delegate void StatusUpdateHandler(string message);
    public event StatusUpdateHandler OnUpdateStatus;

    public void Run()
    {
        OnUpdateStatus("Updated");
    }
}

From you comemnts you have mention that you have huge methods inside the business, and need to display some information on the GUI while the business method is not finished yet the processing.

That become all about threads. With the example I have given above it will work however the UI may not update as the currect thread is too busy doing the work. The UI may even lock up while the background task happens.

If you use just mulitpule threads and the aprach above you will find the issue that you cannot update the UI on another thread.

The background worker thread gets around this issue by doing the work on a 2nd thread but the events fire back to the main UI thread. This keeps the UI respoisive and updated.

 public partial class Form1 : Form
    {
        private BackgroundWorker _backgroundfWorker;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            _backgroundfWorker = new BackgroundWorker();
            _backgroundfWorker.ProgressChanged += OnUpdateStatus;
            _backgroundfWorker.DoWork += backgroundWorker1_DoWork;
            _backgroundfWorker.WorkerReportsProgress = true;
            _backgroundfWorker.RunWorkerAsync();
        }

        private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            var b = new ProjectB();
            b.OnUpdateStatus += ProjectBOnUpdateStatus;
            b.Run();
        }

        private void ProjectBOnUpdateStatus(string message)
        {
            _backgroundfWorker.ReportProgress(0, message);
        }

        private void OnUpdateStatus(object sender,ProgressChangedEventArgs progressChangedEventArgs)
        {
            MessageBox.Show(progressChangedEventArgs.UserState.ToString());
        }
    }
Community
  • 1
  • 1
John
  • 29,788
  • 18
  • 89
  • 130
  • Project A has a referance to B, that is all that is needed with events. I have added a code example so you can see. – John May 11 '17 at 10:23
  • I think form what you say background worker thread is your best apoach as it also supports a ReportProgress as part of the events. – John May 11 '17 at 10:32
  • What is the difference between this approach of events like in your example and the background worker ? I think your example is working fine, no ? – Mehdi Souregi May 11 '17 at 10:36
  • 1
    It is all about threads. With the example I gave it will work however the UI may not update as the currect thread is too busy doing the work. The UI may even lock up while the background task happens. If you use just mulitpule threads and the aprach above you will find the issue that you cannot update the UI on another thread. The background gets around this issue by doing the work on a 2nd thread but the events fire back to the main UI thread. This keeps the UI respoisive and updated. – John May 11 '17 at 10:47
  • no problem I have added a code sample for background worker – John May 11 '17 at 11:00
1

A class library shouldn't reference an assembly that contains user controls and forms. It should be the other way around. Messaging between controls and libraries in WinForms generally happens using events or commands. You definitely shouldn't have code like form1.ErrorMessage = "Something bad happened" in a class library.

i have huge methods inside the business, and i need to display some information on the GUI while the business method is not finished yet the processing

Then you create a ReportProgress event or whatever in the class library, and subscribe to that from the GUI to display the progress.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272