简体   繁体   中英

Invoke from background thread in layered application

Windows forms application, doing heavy processing in separate thread. Somewhere down the processing, I need to take some feedback from user (Like asking some questions about visual output to another device). If I were to do this in UI layer, I would be more than happy to use control's Invoke and do this. The processing is done in business layer. I asked everyone in business layer, no one knows a keyword like Control , Invoke , MainForm etc. How would I notify the Main form and get the input? (events? or am I missing something simple?)

You would need to let your request propagate upwards from the business layer and then invoke it from the presentation layer in your UI.

One way to do this, as you've suggested in your comment, is to use an event that fires from the business layer and is dealt with by your presentation layer, but that depends on whether you want to architect your application to communicate between layers using events.

My own personal preference is to let layers communicate directly with one another, so in this case, I'd have the business layer communicate with the presentation layer that input is requested, and then the presentation layer would marshal the request to the view (UI) itself via Invoke .

One way is to create an event in your business layer from which you connect to from your control/form code. When your control/form receives the event, marshal back onto the UI thread calling Invoke/BeginInvoke in order to update your control(s) accordingly.

Eg in your model code:

public class ModelFoo
{
    public event EventHandler SomethingInterestingHappened;
...

when you call (or broadcast) the event, it's common practice to do this through an "On" method ( make the call thread-safe - see also this ):

    private void
    OnSomethingInterestingHappened
        ()
    {
        var SomethingInterestingHappenedCopy = SomethingInterestingHappened;
        if (SomethingInterestingHappenedCopy != null)
        {
            // TODO add your event data in the second args here
            SomethingInterestingHappenedCopy (this, EventArgs.Empty);
        }
    }

Then subscribe to it from your UI thread, eg:

ModelFoo.SomethingInterestingHappened += SomethingInterestingHappenedHandler;

Where:

    private void SomethingInterestingHappenedHandler(object sender, EventArgs e)
    {
// You can call if(this.InvokeRequired) here, since 
// you might already be on the UI thread. 
// However from other threads call Invoke/BeginInvoke if wanting 
// to process synchronously/asynchronously depending on what you need and
// you need to update a control object.
            Invoke(new MethodInvoker(delegate
            {...

I find events incredibly useful since it feels like you're decoupling the UI from the model nicely. The events can be defined on an Interface also, so the UI code can talk to something abstract which means you can change the underlying type when needed (eg for testing).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM