dextrus
dextrus

Reputation: 1

Newbie: invalid cross thread access using GetAsync

I appreciate GetAsync is, well, asynchronous however I can't find any documentation as to how to use it. At this stage all I want is to get my name and assign that to a text block. Of course if I do this within the _fbClient.GetCompleted += / _fbClient.GetAsync("/me") block, it get the invalid cross thread access exception error.

In the code below the NameTextBlock control is of course set to "[EMPTY]" and some time later the line marked =======> is executed which results in the error.

The few examples I've seen use what appears to be a synchronous Get method but that seems to have gone (and I wouldn't want to use it anyway).

string name = "EMPTY";
        try
        {
            _fbClient.GetCompleted +=
            (o, e) =>
            {
                if (e.Error == null)
                {
                    var result = (IDictionary<string, object>)e.GetResultData();
                    //Dispatcher.BeginInvoke(() => MyData.ItemsSource = result);
                    var tempname = (string)result["name"];
                    name = (string)result["name"];
                    NameTextBlock.Text = "[" + name + "]";
                }
                else
                {
                    MessageBox.Show(e.Error.Message);
                }
            };

            _fbClient.GetAsync("/me");
 //======>      NameTextBlock.Text = "[" + name + "]";


        }
        catch
        {
            MessageBox.Show("Failed.. deal with issues.");
        }
        finally
        {
            NameTextBlock.Text = "[" + name + "]";
        }

Upvotes: 0

Views: 526

Answers (2)

Magnus Johansson
Magnus Johansson

Reputation: 28325

You have the answer in the code snippet you have provided.
Use the Dispatcher.BeginInvoke method like so:

Dispatcher.BeginInvoke(() => NameTextBlock.Text = "[" + name + "]");

Upvotes: 0

Smudge202
Smudge202

Reputation: 4687

The problem you have is a combination of a racing condition, and also that a non-Gui thread is attempting to change a UI element (I forget the correct term for that).

In WPF you use the Dispatcher pattern to resolve the second issue. In Winforms you use the InvokeRequired Pattern.

To combat the racing condition... before calling

_fbClient.GetAsync("/me");

Set the NameTextBlock.Text to "loading..." or "fetching..." or something to that effect. That way when the Asynchronous call completes, it can Populate the text box with the correct details. You may also want to change styling to make it more obvious for the user (like gray when loading, and bright red when you have the result). What you are doing right now is assuming that by the time you set the textbox's text to the name variable, the event (async call) has already completed. This may or may not be the case!

Imagine it in a more simplistic way. Two people at a garage. You send one to open the garage door, the other to drive a van into the garage. In your current code, the guy driving the van is driving into the garage not checking or caring whether the garage door is open yet.

The next issue you have is Thread Safety. The "name" variable can be read from and assigned to simultaneously, meaning the read operation can be operating on volatile memory and may well cause an error/issue - particularly on larger scales!

I would suggest you take a look at Thread Synchronization to get a better idea.

Alot of information to digest there, sorry. Hope it helps though!

Upvotes: 1

Related Questions