Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[C#] [Windows Phone 8] Maps API Invalid cross-thread access

Pagina: 1
Acties:

  • Psycho_Mantis
  • Registratie: Februari 2007
  • Laatst online: 19:20

Psycho_Mantis

Wow. So Amaze.

Topicstarter
Ik loop tegen een vervelend probleem aan, genaamd met de Windows Phone maps API.

In de UI thread werkt de api prima en kan ik routes berekenen, maar ik wil graag ook dat mijn app ook in de achtergrond routes kan berekenen.

Helaas kan je dus met de maps api alleen maar in een UI thread werken, maar de background task heeft natuurlijk geen UI.

Hoe valt hier omheen te werken? Er zijn blijkbaar oplossingen ervoor als je in de Visual Studio Unit Test omgeving werkt zoals omschreven in deze blog

Zoals hieronder in mijn code, kan GeocodeQuery dus niet gebruikt worden op deze manier.

C#: ScheduledAgent.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
            try
            {

                Mygeocodequery = new GeocodeQuery();
                //MemNextLocation bevat de zoekterm waar de route naar berekend moet worden
                Mygeocodequery.SearchTerm = MemNextLocation;
                Mygeocodequery.GeoCoordinate = new GeoCoordinate(MyGeoPosition.Coordinate.Latitude, MyGeoPosition.Coordinate.Longitude);

                Mygeocodequery.QueryCompleted += Mygeocodequery_QueryCompleted;
                Mygeocodequery.QueryAsync();
                
            }
            catch (Exception ex)
            {
                //Hier krijgen we de Invalid cross-thread access
                Debug.WriteLine(ex.Message);
            }


Als iemand me al een duwtje in de goede richting kan geven :)

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Ik heb nog geen ervaring met de Maps API, maar ik verwacht dat het alles te maken heeft met de huidige Synchronisation context. ( Voor WPF, en ik neem aan op windows phone een vergelijkbare: MSDN: DispatcherSynchronizationContext Class (System.Windows.Threading) ) Ik verwacht dat je in ieder geval met een custom synchronisation context wel wat moet kunnen bereiken.

Maar misschien zijn er wel mooiere oplossingen, maar daarvoor weet ik even niet genoeg van de Maps API. Ik vond wel deze link, misschien dat je daar wat aan hebt: http://channel9.msdn.com/Events/Build/2012/2-017

Verder is het natuurlijk niet zo'n probleem om de async calls op de UI thread te doen, aangezien het toch async is zal het niet blokkeren. ( Dat is ook gewoon wat er in de unit test case gebeurd, de request wordt d.m.v. de huidige dispatcher op de juiste thread geinvoked )

[ Voor 51% gewijzigd door Woy op 26-08-2013 22:42 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


  • pedorus
  • Registratie: Januari 2008
  • Niet online
Als je echt geen UI thread hebt, dan is er een probleem natuurlijk. Anders is de synchronisatie vrij eenvoudig, die andere post gebruikt ook gewoon simpele synchronisatie zoals http://stackoverflow.com/a/8006644. De vraag is dus hoe je code op een UI thread kan uitvoeren, of dat je dit kan faken (helaas is GeocodeQuery sealed, anders was dit eenvoudig, maar je zou even naar de source van CheckThread kunnen kijken) ;)

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
pedorus schreef op dinsdag 27 augustus 2013 @ 00:20:
Als je echt geen UI thread hebt, dan is er een probleem natuurlijk.
Ik verwacht dat er niet daadwerkelijk een UI thread nodig is, maar dat je het op de thread van de huidige dispatcher moet doen, en dat CheckThread dus gebruik maakt van Dispatcher.Current.CheckAcces ( MSDN: Dispatcher.CheckAccess Method (System.Windows.Threading) ). Nou weet ik eigenlijk niet zeker of er op een background task uberhaupt een Dispatcher is.

[ Voor 7% gewijzigd door Woy op 27-08-2013 08:05 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


  • Psycho_Mantis
  • Registratie: Februari 2007
  • Laatst online: 19:20

Psycho_Mantis

Wow. So Amaze.

Topicstarter
Bedankt voor de reacties!
Ik ga van de week er even een avondje voor zitten :)

  • Psycho_Mantis
  • Registratie: Februari 2007
  • Laatst online: 19:20

Psycho_Mantis

Wow. So Amaze.

Topicstarter
Het Invalid cross-thread access probleem lijkt opgelost.
Dus misschien interessant om te weten dat GeocodeQuery() niet als async gebruikt kan worden.

Heb toch nog lichtelijk het vermoeden dat Mygeocodequery.QueryAsync() nog niet helemaal werkt naar behoren, maar dat ligt waarschijnlijk weer aan een stuk code veder op.
Helaas vandaag geen tijd om veder te debuggen wat er fout gaat, maar mijn dank is al groot dat ik al weer een stap dichterbij ben. :)

Ik heb hier in mijn code dus het stukje van stackoverflow ingeplakt:

C#: ScheduledAgent.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
     private async void GetCoordinates() //private async void
        {
            // Get the phone's current location.
            Geolocator MyGeolocator = new Geolocator();
            MyGeolocator.DesiredAccuracyInMeters = 5;
            Geoposition MyGeoPosition = null;
            try
            {
                MyGeoPosition = await MyGeolocator.GetGeopositionAsync(TimeSpan.FromMinutes(1), TimeSpan.FromSeconds(10));
                MyCoordinates.Add(new GeoCoordinate(MyGeoPosition.Coordinate.Latitude, MyGeoPosition.Coordinate.Longitude));
            }
            catch (UnauthorizedAccessException)
            {
                //Location settings off?
            }
            catch (Exception ex)
            {
                // Something else happened while acquiring the location.
               // MessageBox.Show(ex.Message);
            }
            try
            {
                Exception exception = null;
                var waitEvent = new System.Threading.ManualResetEvent(false);
                 Deployment.Current.Dispatcher.BeginInvoke(() =>
                {
                    try
                    {
                        Mygeocodequery = new GeocodeQuery();
                        Mygeocodequery.SearchTerm = MemNextLocation;
                        Mygeocodequery.GeoCoordinate = new GeoCoordinate(MyGeoPosition.Coordinate.Latitude, MyGeoPosition.Coordinate.Longitude);

                        Mygeocodequery.QueryCompleted += Mygeocodequery_QueryCompleted;
                        Mygeocodequery.QueryAsync();
                        Debug.WriteLine("Location calculation succesfull");
                    }
                    catch (Exception ex)
                    {
                        exception = ex;
                        Debug.WriteLine("Exception id1: " + ex.Message);
                    }
                    waitEvent.Set();
                });
                waitEvent.WaitOne();
                if (exception != null)
                    throw exception;


            }
            catch (Exception ex)
            {
                //cannot find this location, or something else happend
                Debug.WriteLine("Exception id2: " + ex.Message);
            }

        }

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Wellicht wil je waitEvent.Set(); pas doen in Mygeocodequery_QueryCompleted of bij een exception. In ieder geval zal die functie vanuit de andere thread aangeroepen worden (of wellicht niet bij een fout), en dat is iets om rekening mee te houden.

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Psycho_Mantis schreef op dinsdag 27 augustus 2013 @ 16:48:
Ik heb hier in mijn code dus het stukje van stackoverflow ingeplakt:
Ik heb het idee dat je de klok hebt horen luiden maar weet je niet waar de klepel hangt ;)

Je definieert nu een async methode, die vervolgens alleen op GetGeopositionAsync await. Daarna probeer je een GeoQuery uit te voeren, en maak je je async methode blocking, terwijl je ook nog niet op het juiste blokt ( Zoals pedorus inderdaad opmerkt ), want aan het eind is de GeoQuery nog niet uitgevoerd, alleen de async methode is gestart. Ik vraag me ook af of het opvangen van de exception zo nodig is, want meestal gooit het opstarten van een async operatie geen exception, en als dat hier ook niet het geval is, is je hele waithandle overbodig.

Op zich zou je code best kunnen werken, maar ik zou je aanraden om van te voren goed te bedenken wat de pre- en postcondities van je method zijn. Verder weet ik ook niet precies hoe async en await afgehandeld wordt in een background task in WP8, dat heeft weer alles te maken met de SynchronisationContext, dus daar zit misschien ook nog een probleem.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


  • Psycho_Mantis
  • Registratie: Februari 2007
  • Laatst online: 19:20

Psycho_Mantis

Wow. So Amaze.

Topicstarter
Aha dat zou wellicht kunnen verklaren waarom Mygeocodequery_QueryCompleted wel uitgevoerd word maar alles wat daarna komt niet.

En inderdaad, ik ben nog niet erg ervaren met het gebruik threads.

Ik ga me nog wat meer inlezen hierin en kijken of ik het werkend krijg. :)


Edit:

Ja dat was dus het probleem, het werkt nu _/-\o_
Bedankt voor jullie hulp!

[ Voor 14% gewijzigd door Psycho_Mantis op 28-08-2013 20:31 ]

Pagina: 1