views:

38

answers:

3

Basically, I'm getting some data from a WebService, and in the ResponseCallback I'm trying to fill an ObservableCollection with the results I got from the response, but I get an UnauthorizedAccessException "Invalid cross-thread access" when I try to do so.

What would be the best way to fill said observable collection when I get the result?

Thanks!

This is the code:

    public ObservableCollection<Person> People { get; set; }

    private void ResponseCallback(IAsyncResult asyncResult)
    {
        HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState;
        HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asyncResult);

        string responseString = string.Empty;

        using (Stream content = response.GetResponseStream())
        {
            if (request != null && response != null)
            {
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    XDocument document = XDocument.Load(content);

                    var people = from p in document.Descendants()
                            where p.Name.LocalName == "PersonInfo"
                            select Person.GetPersonFromXElement(p);

                    foreach (Person person in people)
                    {
                        this.People.Add(person); // this line throws the exception
                    }
                }
            }

            content.Close();
        }
    }
+2  A: 

You might want to have a look at this http://codeblitz.wordpress.com/2009/05/27/handling-cross-threading-in-observablecollection/

climbage
Thanks for the suggestion, but I'm not really sure about putting this solution in production code.
Carlo
Also apparently the solution doesn't work in Windows Phone 7. I didn't say this was what I was using at first, but now I added it to the title / tags. Thanks.
Carlo
gotcha. I have no experience with phone 7.. so good luck!
climbage
A: 

Hi Carlo,

If you want to update the UI (even indirectly via an observed collection) from another thread you just need to use the dispatcher as follows:

Dispatcher.BeginInvoke( () => { //your ui update code } );
Mick N
Yeah, the thing is that the code I posted is in my view model, and I don't want to make my view model inherit from DependencyObject just for that. We're trying to keep memory low, and DependencyObject are very resource costly.
Carlo
A: 

Hello, I have exactly same problem on WP7. It can be solved by the code Mick N suggested and with no need to inheriting from DO. Just take a Dispatcher from static Deployment class.

Deployment.Current.Dispatcher.BeginInvoke( () => { //your ui update code } );

But this seems to me kind of weird solution, I've never have to do this in desktop Silverlight.

Is this WP7 specific or is there some better solution? Thanks.

jumbo
It is WP7 specific. What I did is that I'm sending the dispatcher of the UserControl that called the ViewModel.Load() method. It looks like: App.MainViewModel.Load(this.Dispatcher); and inside I use that dispatcher to make the async operation, not sure if it's the best way, but it works.
Carlo
Well, with the approach above, you don't need to pass anything. There is always one Dispatcher waiting for you in that Deployment class. Either way, this means that since our apps are internet based, our code will be full of Dispatchers, am I right?
jumbo
Ok, with WebClient downloads works everything ok (binded ObservableCollection is filled without need of Dispatcher), but when I use RestSharp lib (for WP7), I have to fill the ObsColl through Dispatcher.
jumbo