MadBoy
MadBoy

Reputation: 11104

How to get return value when BeginInvoke/Invoke is called in C#

I've this little method which is supposed to be thread safe. Everything works till i want it to have return value instead of void. How do i get the return value when BeginInvoke is called?

public static string readControlText(Control varControl) {
        if (varControl.InvokeRequired) {
            varControl.BeginInvoke(new MethodInvoker(() => readControlText(varControl)));
        } else {
            string varText = varControl.Text;
             return varText;
        }

    }

Edit: I guess having BeginInvoke is not nessecary in this case as i need value from GUI before the thread can continue. So using Invoke is good as well. Just no clue how to use it in following example to return value.

private delegate string ControlTextRead(Control varControl);
    public static string readControlText(Control varControl) {
        if (varControl.InvokeRequired) {
            varControl.Invoke(new ControlTextRead(readControlText), new object[] {varControl});
        } else {
            string varText = varControl.Text;
             return varText;
        }

    }

But not sure how to get value using that code either ;)

Upvotes: 53

Views: 73006

Answers (7)

Krish
Krish

Reputation: 646

Here is more cleaner solution

    public delegate void InvokeIfRequiredDelegate<T>(T obj) where T : ISynchronizeInvoke;
    public static void InvokeIfRequired<T>(this T obj, InvokeIfRequiredDelegate<T> action) where T : ISynchronizeInvoke
    {
        if (obj.InvokeRequired)
            obj.Invoke(action, new object[] { obj });
        else
            action(obj);
    }

    public static string GetThreadSafeText(this Control control)
    {
        string value = string.Empty;
        control.InvokeIfRequired((c) => value = c.Text);
        return value;
    }
    public static void SetThreadSafeText(this Control control, string value)
    {
        control.InvokeIfRequired((c) => c.Text = value);
    }

Usage:

    public string Name
    {
        get => txtName.GetThreadSafeText();
        set => txtName.SetThreadSafeText(value);
    }

Upvotes: 0

Pablo
Pablo

Reputation: 1

delegate string StringInvoker();
    string GetControlText()
    {
        if (control.InvokeRequired)
        {
            string controltext = (string)control.Invoke(new StringInvoker(GetControlText));
            return(controltext);
        }
        else
        {
            return(control.Text);
        }
    }

//simple & elegant but it is needed to wait for another thread to execute delegate; however if you cannot proceed without the results...

Upvotes: 0

Justin Ethier
Justin Ethier

Reputation: 134157

EndInvoke may be used to get a return value from a BeginInvoke call. For example:

    public static void Main() 
    {
        // The asynchronous method puts the thread id here.
        int threadId;

        // Create an instance of the test class.
        AsyncDemo ad = new AsyncDemo();

        // Create the delegate.
        AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);

        // Initiate the asychronous call.
        IAsyncResult result = caller.BeginInvoke(3000, 
            out threadId, null, null);

        Thread.Sleep(0);
        Console.WriteLine("Main thread {0} does some work.",
            Thread.CurrentThread.ManagedThreadId);

        // Call EndInvoke to wait for the asynchronous call to complete,
        // and to retrieve the results.
        string returnValue = caller.EndInvoke(out threadId, result);

        Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",
            threadId, returnValue);
    }
}

Upvotes: 20

Sergey Teplyakov
Sergey Teplyakov

Reputation: 11647

public static string readControlText(Control varControl)
{
    if (varControl.InvokeRequired)
    {
        string res = "";
        var action = new Action<Control>(c => res = c.Text);
        varControl.Invoke(action, varControl);
        return res;
    }
    string varText = varControl.Text;
    return varText;
}

Upvotes: 4

Hans Passant
Hans Passant

Reputation: 941465

You have to Invoke() so you can wait for the function to return and obtain its return value. You'll also need another delegate type. This ought to work:

public static string readControlText(Control varControl) {
  if (varControl.InvokeRequired) {
    return (string)varControl.Invoke(
      new Func<String>(() => readControlText(varControl))
    );
  }
  else {
    string varText = varControl.Text;
    return varText;
  }
}

Upvotes: 84

Randy Minder
Randy Minder

Reputation: 48402

Is something like this what you wanted?

// begin execution asynchronously
IAsyncResult result = myObject.BeginInvoke("data.dat", null, null);

// wait for it to complete
while (result.IsCompleted == false) {
   // do some work
   Thread.Sleep(10);
   }

// get the return value
int returnValue = myObject.EndInvoke(result);

Upvotes: 1

THX-1138
THX-1138

Reputation: 21730

If you want a return value from you method, you shouldn't be using async version of the method, you should use .Invoke(...). Which is synchronous, that is it will execute your delegate, and won't return until it's complete. In your example as it is now, BeginInvoke will send the request to execute your delegate, and return right away. So there is nothing to return.

Upvotes: 1

Related Questions