-2

I have two methods:

private async Task<GeoCoordinate> CenterMapOnMyLocation()
    {
        Geolocator myGeolocator = new Geolocator();
        Geoposition myGeoposition = await myGeolocator.GetGeopositionAsync();          
        Geocoordinate myGeocoordinate = myGeoposition.Coordinate;
        GeoCoordinate myGeoCoordinate =
            ConvertGeocoordinate(myGeocoordinate);

        MapCenter = myGeoCoordinate;
        if (MyLocation.Latitude == 0 && MyLocation.Longitude == 0)
        {
            MyLocation = MapCenter;
        }

        return myGeoCoordinate;
    }

and

private void GetClosestLocations(GeoCoordinate myLocation)
    {
        var locations = new ObservableCollection<PushPinModel>
                    {
                        new PushPinModel
                            {
                                Location = new GeoCoordinate(51.569593, 10.103504),
                                LocationName = "1"
                            },
                        new PushPinModel
                            {
                                Location = new GeoCoordinate(-45.569593, 1.103504),
                                LocationName = "2"
                            },
                        new PushPinModel
                            {
                                Location = new GeoCoordinate(0, 0),
                                LocationName = "3"
                            }
                    };
        foreach (var location in locations)
        {
            location.DistanceToMyLocation = HaversineDistance(myLocation, location.Location);
        }

        Treks = new ObservableCollection<PushPinModel>(locations.OrderBy(l => l.DistanceToMyLocation).Take(2).ToList());
    }

and in the constructor I have something like this:

public NearbyControlViewModel()
    {
        var test = CenterMapOnMyLocation();
        GetClosestLocations(test);
    }

Now, my problem is that when the second method is called in the constructor, the "test" variable is not initialized yet... because it's async. What I want to do is wait for it to get initialized and after that call the second method. If I call my second method from the async method I get an exceptions: InvalidOperationException - Collection is in non writeable mode. "Treks" value is binded to a MapItemsControl. So i guess the problem something about threads.

Rares Felecan
  • 358
  • 3
  • 17

3 Answers3

2

You need to use asynchronous initialization. I give a few different solutions in my blog post on async construction.

Note that asynchronous code forces you to have a better UI design. I.e., you must design some kind of "before the map is centered" state for your UI. The UI will initially start in that state, and then when the (asynchronous) initialization is complete, the UI is updated.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
1

If it wasn't the constructor:

public async Task SomeMethod()
{
    var test = await CenterMapOnMyLocation();
    GetClosestLocations(test);
}

But - with the constructor? perhaps simply don't do that. Trying to wait in a constructor could be deadly - especially in some sync-contexts - that could deadlock immediately.

Consider making it something that you start after the constructor.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • @I4V ah, didn't realise it was the constructor! Indeed, in that case: *don't do that* :p – Marc Gravell May 10 '13 at 12:14
  • I did what you said here: created a new class "SomeMethod" and called it in the constructor, but again i get the Exception. – Rares Felecan May 10 '13 at 12:20
  • @RaresFelecan what exception are you getting now? what is referring to `test` ? it can't be `SomeMethod`, because that is going to `await`... but again: calling any of this in a constructor seems a fundamentally *bad idea*. Why do you want to call this from a constructor? – Marc Gravell May 10 '13 at 12:25
  • Ok, lets see if I can be more clear. Take a look here: http://stackoverflow.com/questions/16417978/mvvm-windows-phone-8-adding-a-collection-of-pushpins-to-a-map/16441672#16441672. I'm getting the exception at this line for DependencyProperty: pushpin.ItemsSource = (IEnumerable)e.NewValue; – Rares Felecan May 10 '13 at 12:35
0

You can add a test.Wait(); before calling GetClosestLocation; after all, you are getting a Task from CenterMapOnMyLocation. (EDIT: But indeed, Marc is right, waiting there is evil. You should probably refactor to call the async code outside the constructor.)

zsgalusz
  • 76
  • 5