0

i have a problem with Winforms app with 2 threads: in a second thread I pull messages from WCF service. When there are messages I need to update the GUI : I do this in accordance with patten found here How to update the GUI from another thread in C#? . Here is the code:

     private delegate void CWU(int ID); 
    public void AddNewTab(int id)
    {
        if (this.tabControl1.InvokeRequired)
        {
            CWU cb = new CWU(AddNewTab);
            this.tabControl1.Invoke(cb,id);
        }
        else
        {
            User ToChatWith = ContactsHelper.AllFriends.Find(e => e.ID == id);
            tabpage.Text = ToChatWith.ToString();
            this.tabControl1.TabPages.Add(tabpage);
            this.tabControl1.SelectTab(tabpage);
        }

tab is added properly and when we leave this method the app is not responding, no info in debug. When I run my app after adding this tab i get AppHangB1 without any details. Can you help me?

Community
  • 1
  • 1
P3k1
  • 90
  • 9
  • What does AddRTB do ? Did you mean AddNewTab instead ? – Thomas Levesque Jan 16 '13 at 21:38
  • it was an old code, it is CWU cb = new CWU(AddNewTab); , sorry – P3k1 Jan 16 '13 at 21:43
  • How often do you call AddNewTab from the other thread? Consider activating exceptions (menu Debug/Exceptions) and see if anything gets thrown. – Marcel N. Jan 16 '13 at 21:51
  • only when new message for user for whom there is no tab. during my tests it was called only once per run. – P3k1 Jan 16 '13 at 21:55
  • Most often this kind of problem is caused by a busy `main` thread. Maybe it is busy waiting for the other thread to finish? (i.e.: `click event` -> `AddNewTab` -> `Invoke`; and Invoke would like to have click event finish first), You could try `BeginInvoke` but this will cause the changes to be delayed a bit. – Jan-Peter Vos Jan 16 '13 at 21:59
  • 2
    Where is `tabpage` being created? Could it be getting added more than once? Also, assuming it takes some time to process, wouldn't it be better to create ToChatWith in the worker thread rather than the GUI thread? –  Jan 16 '13 at 22:05
  • I have also tried BeginInvoke: the same effect. – P3k1 Jan 16 '13 at 22:08
  • TabPage tabpage = new TabPage(); is a field of Chat form, and this form is created when there is only one thread. I wanted tabpage to be modified and added more than once. – P3k1 Jan 16 '13 at 22:11
  • Yes, there's only one `tabpage` object, so if this method is invoked twice externally, then you're going to have problems. Note: You can probably solve this yourself by adding breakpoints to both closing brackets `}` in your example and F5'ing to them. (Be sure to step-through after the last one gets hit) –  Jan 16 '13 at 22:15
  • @ebyrob tabpage is added properly, I will fix tabpages logic when app will not hang :) – P3k1 Jan 16 '13 at 22:16
  • Try to initialize the `tabpage` inside the `else{}` scope. – Alex Filipovici Jan 16 '13 at 22:16
  • Also, you may try adding ` System.Diagnostics.Debugger.Break();` as the first line inside the `else{}` statement and start debugging. – Alex Filipovici Jan 16 '13 at 22:28
  • @AlexFilipovici nope, it is still hanging. I have found that when leaving AddNewTab i have 3 threads in callstack: Komunikator.exe!Komunikator.Chat.AddNewTab(int id) Line 75 C# ---------------------------------- Komunikator.exe!Komunikator.Chat.MessageReceived(int id, DataContracts.Message message) Line 128 + 0xb bytes C# ---------------------------------- Komunikator.exe!Komunikator.Transmission.backgroundWorker_DoWork() Line 33 + 0x47 bytes C# and one position [external code]. When I leave this method I have only DoWork thread and [external code] – P3k1 Jan 16 '13 at 22:33

3 Answers3

0

Try this:

if (this.InvokeRequired)
{
    this.Invoke((MethodInvoker)delegate
    {
        AddNewTab(id);
    });
}
Alex Filipovici
  • 31,789
  • 6
  • 54
  • 78
  • the same with your code @Alex and with ' if (this.tabControl1.InvokeRequired) { this.tabControl1.Invoke((MethodInvoker)delegate { AddNewTab(id); }); }' – P3k1 Jan 16 '13 at 22:03
0

Invoke can hang if the called thread is busy doing something. (You could know this is the case if a BeginInvoke call instead of your Invoke wouldn't hang. Invoke blocks until the call is made successfully, BeginInvoke does not.)

canahari
  • 512
  • 1
  • 4
  • 9
0

Replace your method with this:

    private void dbg(string s)
    {
        System.Diagnostics.Debug.WriteLine("AddNewTab({0}): {1}", 
            Thread.CurrentThread.ManagedThreadId, s);
    }
    public void AddNewTab(int id)
    {
        try
        {
            dbg("entered");
            if (this.tabControl1.InvokeRequired)
            {
                new Thread(delegate() { try {
                        CWU cb = new CWU(AddNewTab);
                        dbg("calling Invoke");
                        this.tabControl1.Invoke(cb, id);
                        dbg("Invoke returned");
                    } catch (Exception ex) { dbg("" + ex); }
                }).Start();
                dbg("created sub-thread");
            }
            else
            {
                dbg("setting tabpage.Text");
                User ToChatWith = ContactsHelper.AllFriends
                    .Find(e => e.ID == id);
                tabpage.Text = ToChatWith.ToString();
                dbg("adding tab");
                this.tabControl1.TabPages.Add(tabpage);
                this.tabControl1.SelectTab(tabpage);
                dbg("done adding tab");
            }
            dbg("leaving");
        }
        catch (Exception ex)
        {
            dbg("" + ex);
        }
    }

Make sure you can find the debugger output in your environment. (Heck, use Console.WriteLine if that helps)

If that doesn't help you diagnose the problem I don't know what will.