-1

In my application I had a requirement of notifying the user about the pending applications.

So in the mdiParent I set a BackgroundWorker which keeps querying the database to get any pending application, and if it finds any display it on the Tooltip on the MdiParent

private void button1_Click(object sender, EventArgs e)
{
    backgroundWorker1.RunWorkerAsync(2000);
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    fillnotification();
}    

public void fillnotification()
{
    int pending = 0;
    if( Program.USERPK != 0)
    {    
        DataTable dt = nftrans.getnotification();
        pending = dt.Rows.Count;

        String message = "You Have  " + pending + " Applications Pending For Approval";

        // toolTip1.SetToolTip(lblStatus , message);
        toolTip1.Show(message , this, lblStatus.Location);
    }
}

but when I run the solution I am getting an exception:

Cross-thread operation not valid: Control 'MainForm' accessed from a thread other than the thread it was created on.

I understand its due to two different threads but cannot sort this out. Can any one suggest a solution? I tried the ideas I read in related questions But cannot find a correct solution

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
Sreenath Ganga
  • 696
  • 4
  • 19
  • 48

4 Answers4

2

Anytime you are accessing a control from an outside thread (the background worker Executes an operation on a separate thread.) you need to do some sort of invoke. This executes a delegate on the thread that owns the underlying window handle.

Something simple like ;

        this.Invoke(new MethodInvoker(delegate()
        {
        //   toolTip1.SetToolTip(lblStatus , message);
        toolTip1.Show(message, this, lblStatus.Location);

        }));

Will probably work for your case, as long as your previous code is not accessing controls, I'm not sure what getnotification() is doing.

clamchoda
  • 4,411
  • 2
  • 36
  • 74
1

You are changing the UI (tooltip) on the worker thread.

That is not allowed. Use the UI thread to change the tooltip by calling Invoke on the Window and passing a delegate to a function that changes the the tooltip.

Emond
  • 50,210
  • 11
  • 84
  • 115
1

Since it appears that the change of tooltip happens at the exact end of your worker thread, you could use the RunWorkerCompleted event - you CAN modify the UI thread from there, and that's what this event was designed for.

Of course Chris Bucklers Invoke solution will also work.

MBender
  • 5,395
  • 1
  • 42
  • 69
0

Change fillnotification() to return your pending value and pass that to "e.Result" in your DoWork() handler. Now wire up the RunWorkerCompleted() event and retrieve the result of your background operation:

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        e.Result = fillnotification();
    }

    public int fillnotification()
    {
        if (Program.USERPK != 0)
        {
            DataTable dt = nftrans.getnotification();
            return dt.Rows.Count;
        }
        return -1;
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        int pending = (int)e.Result;
        if (pending != -1)
        {
            String message = "You Have  " + pending.ToString() + " Applications Pending For Approval";
            toolTip1.Show(message, this, lblStatus.Location);
        }
    }
Idle_Mind
  • 38,363
  • 3
  • 29
  • 40