C# cross-thread call problem
Asked Answered
H

3

1

I'm writing a form app in c# and I need to be able to change the contents of a Rich Text Box from any thread, I tried using a delegate and InvokeRequired, but the delegate I made still gives me a cross-thread call error, and InvokeRequired crashes the form, without giving an error. Function I need to be able to execute from any thread:

    public static void updateSub(int what)
    {
        subDisplay.subBox.Text = tb[what];
    }

The delegate I tried to use:

    public delegate void UpdateDelegateVoid(int what);
    static public UpdateDelegateVoid uSub = new UpdateDelegateVoid(updateSub);
    uSub(0);

My InvokeRequired code:

    public static void updateSub(int what)
    {
        if (subDisplay.subBox.InvokeRequired)
        {
            subDisplay.subBox.Invoke(new MethodInvoker(finish));
        }
        else
        {
            subDisplay.subBox.Text = tb[what];
        }
    }

I'm not really sure why the code above isn't working. Thanks!

Hack answered 28/4, 2011 at 8:44 Comment(4)
Sorry but, what is finish? What is MethodInvoker?Vauntcourier
Whats this bit do subDisplay.subBox.Invoke(new MethodInvoker(finish)) and why is it in a static method, surely it should on the instance of subDisplay. Is subDisplay a static property?Riannon
@Martinho: MethodInvoker exists till .Net 1.1 and was used before Action arised.Oteliaotero
To get more closer to the point where the exception occurs you should open in Visual Studio Debug - Exceptions and check all checkboxes. In this case the compiler will break before the exception will be thrown.Oteliaotero
A
3

Strictly speaking, when you check InvokeRequired and find it's true, you should marshall the call to the same method. I'm not sure it fixes your specific problem (I'd need to see more exception details and code) but this is what I mean:

public static void updateSub(int what)
{
    if (subDisplay.subBox.InvokeRequired)
    {
        subDisplay.subBox.Invoke(new Action<int>(updateSub), what);
    }
    else
    {
        subDisplay.subBox.Text = tb[what];
    }
}

If you're getting "weird behaviour", then check that the form is actually created on the main application thread. In WinForms this isn't forced (as it is in WPF) so it's just possible that the thread that the form was created on isn't actually the root thread of the app.

Absently answered 28/4, 2011 at 8:56 Comment(7)
But this won't work. MethodInvoker is a delegate for invoking methods without parameters and return value. But updateSub has an int parameter ...Eads
@Neil Umm, the reason MethodInvoker was 'crashing' the form is that I accidentally put MethodInvoker(finish) instead of MethodInvoker(updateSub), I assume it would work if I'd change that... Though, I have found a way to make a valid cross-thread call: ` displaySub.Invoke((MethodInvoker)delegate { subDisplay.subBox.Text = tb[what]; });`Hack
@George: so, you weren't actually getting a cross-thread error, right?Vauntcourier
@Eads Good point, and exactly why SO should have a compiler built-in. :) I've updated to the generic Action instead.Absently
@Martinho: I was getting a cross-thread error when I used a delegate, though the 'form crashing' I was getting while using MethodInvoke was just cause by my stupidity... :)Hack
Yes, SO definetly needs a compiler ... and Notepad++ as well ;-)Eads
@takrl: it doesn't really shine in a WinForms question like this, but maybe you should try LINQPad.Vauntcourier
G
2

I mostly use this, and it works perfectly. For the exact same purpose are what you are intending.

public void UpdateSub(string message)
{
    subDisplay.subBox.Invoke((Action)delegate {
        subDisplay.subBox.Text = message;
    });
}

Hope it help's your or someone else with it!

Grappa answered 28/4, 2011 at 9:15 Comment(0)
V
1

Try this - where you call the same method if an invoke is required.

public void UpdateSub(string message)
{
    if (!subDisplay.subBox.InvokeRequired)
    {
        subDisplay.subBox.Text = message;
    }
    else
    {
        var d = new UpdateFormText(UpdateSub);
        Invoke(d, new object[] { message });
    }
}

Where UpdateFormText is the delegate

public delegate void UpdateFormText(string message);
Vachon answered 28/4, 2011 at 8:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.