Bob
Bob

Reputation: 4386

.NET muti threading. Updating the UI on the fly

I have a button click event and inside I do a lot of work.

While I am doing this work (not from the UI project) I want to send messages to the UI to display to the user.

I am doing something like:

    void Button_Click(object sender, EventArgs e)
    {
        DoMyWork(SendMessage);
    {

    public void SendMessage(string message)
    {
        TextBox1.Text = message + "\n"; 
    }

and inside DoMyWork which is in another assembly i can call SendMessage which writes to the textbox. The messages will only display though when DoMyWork is complete.

How can I update TextBox1.Text on the fly without putting DoMyWork on a BackGround thread or do i have to put it on a BackGround thread? I do actually want to block the user from doing anything while DoMyWork is running

thanks

Upvotes: 2

Views: 823

Answers (9)

Geoffrey
Geoffrey

Reputation: 976

The code I usually use for these kind of purposes is, it is originally for catching an UpdateStatus event from a child user control, but should work equally well for this.

    Delegate Sub SetStatus(ByVal sender As Object, ByVal text As String)

    Private Sub UpdateStatus_Event(ByVal sender As Object, ByVal str As String)
     If tsStatus.InvokeRequired Then
        Dim delStatus As New SetStatus(AddressOf UpdateStatus_Event)
        Me.Invoke(delStatus, New Object() {sender, str})
     Else
        tsStatus.Text = str
        Application.DoEvents()
     End If
    End Sub

    Private Sub btn_Click(Byval sender as Object, Byval e as EventArgs) Handles btn1.Click
     Dim oTh as New Threading.Thread(AddressOf WorkSub)
     oTh.Start()
    End Sub

    Private Sub WorkSub()
     ALotOfWork()
     UpdateStatus_Event(btn1,"message")
    End Sub

Upvotes: 0

John
John

Reputation: 392

either working this as a task or a background worker is the best solution. however you can pump messages from a regular thread to the UI...

you need a delegate sub - in the thread class

delegate void UpdateTextHandler(string msg);

code inside the thread

private void UpdateUI(string msg)
{
    form1 f = My.Application.OpenForms("form1 ");
    f.Invoke(new UpdateTextHandler(f.UpdateLabel), new object[] { msg });
}

code inside the UI

public void UpdateLabel(string msg)
{
    label1.Text = msg;
}

Basically what you are trying to do here is just invoke the actual thread that has the UI and send it a message.

Unfortunately this doesn't really prevent the user from actually not being able to be anything. You would have to do through and disable controls as well.

Upvotes: 0

gjvdkamp
gjvdkamp

Reputation: 10536

Don't know about your developement status, you probably can't wait out for C# 5. But you should take a look at what's coming in this field with the "async - await" language features: http://msdn.microsoft.com/en-us/vstudio/async.aspx The current approach can be a bit hard to get you head around but they've really fixed that.

GJ

Upvotes: 0

Bryan
Bryan

Reputation: 2791

BackgroundWorker is a great class. If you don't want the user to use the form while your process is running, you can set its Enabled property to false. But you don't want to block the UI thread during your long running process.

Upvotes: 0

Brian Gideon
Brian Gideon

Reputation: 48979

You really need to put long running operations on a separate thread. If you do not then the UI will become unresponsive and the user will think it has hung up. There are two common ways of getting the worker thread started.

There are two generally accepted methods for updating the UI safely with data generated by the worker thread.

  • Have the worker thread push the notification via Control.Invoke.
  • Have the UI thread poll a shared data structure periodically which is updated by the worker thread.

The BackgroundWorker class inherently uses the push method (via Control.Invoke) to report progress when using the ReportProgress method in conjuction with the ProgressChanged event.

Creating a thread manually allows you to have better control over how the UI and worker thread interactions take place in exchange for having to wire up all the plumbing yourself.

Since I do not know the details of the long running operation nor the nature of the messages that need to be displayed I cannot say for certain direction will work best for you. Starting off with BackgroundWorker approach will probably be okay.

Upvotes: 1

Kell
Kell

Reputation: 3327

Call Application.DoEvents(); after setting the textbox text

Upvotes: -1

Artemiy
Artemiy

Reputation: 1979

to update UI from another thread use Control.Invoke method - as previously mentioned. You may use BackgroundWorker to actually do work in another thread (otherwise UI becomes non-responsive) or roll your own thread - BackgroundWorker is just a helper class, but makes is much simpler

Upvotes: 0

alpha-mouse
alpha-mouse

Reputation: 5003

You may use BackgroundWorker. Further reading

Upvotes: 4

Nick
Nick

Reputation: 13444

You need to place the code in a thread. Before launching the thread, disable any UI. When the thread dies, re-enable the UI.

When updating the UI from a worker thread, use the Invoke method on a Control, because all UI changes must come from the "UI Thread".

Upvotes: 2

Related Questions