本文介绍了如何等待 QueryCompleted 事件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个小型测试应用程序来获取经度和纬度并将其转换为实际地址:

I created a small test application to get the Longitude and Latitude and to convert it to the actual address:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Device.Location;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Maps.Services;
using Microsoft.Phone.Shell;
using PhoneApp1.Resources;
using Windows.Devices.Geolocation;

namespace PhoneApp1
{
public partial class MainPage : PhoneApplicationPage
    {
    private GeoCoordinate Location;
    public ObservableCollection<string> Addresses { get; set; }

    // Constructor
    public MainPage()
        {
        InitializeComponent();

        // Sample code to localize the ApplicationBar
        //BuildLocalizedApplicationBar();
        }

    protected override async void OnNavigatedTo( NavigationEventArgs e )
        {
        await GetLocation();
        }

    public async Task GetLocation()
        {
        Location = await CoordinateConverter.GetLocation();

        ReverseGeoCoding.StartReverseGeoCoding( Location );

        //ReverseGeoCoding.done.WaitOne();

        string Address = ReverseGeoCoding.Address;
        }
    }

public static class ReverseGeoCoding
    {
    public static ObservableCollection<string> Addresses = new ObservableCollection< string >();
    public static string Address;
    public static bool Completed;
    public static AutoResetEvent done = new AutoResetEvent( true );

    public static void StartReverseGeoCoding( GeoCoordinate Location )
        {
        Completed = false;
        var reverseGeocode = new ReverseGeocodeQuery();
        reverseGeocode.GeoCoordinate = new GeoCoordinate( Location.Latitude, Location.Longitude );
        reverseGeocode.QueryCompleted += ReverseGeocodeQueryCompleted;
        done.Reset();
        reverseGeocode.QueryAsync();
        }

    public static void ReverseGeocodeQueryCompleted( object sender, QueryCompletedEventArgs<System.Collections.Generic.IList<MapLocation>> e )
        {
        var reverseGeocode = sender as ReverseGeocodeQuery;
        if ( reverseGeocode != null )
            {
            reverseGeocode.QueryCompleted -= ReverseGeocodeQueryCompleted;
            }

        //Microsoft.Phone.Maps.Services.MapAddress address;
        Addresses.Clear();
        if ( !e.Cancelled )
            {
            foreach ( var address in e.Result.Select( adrInfo => adrInfo.Information.Address ) )
                {
                Addresses.Add( string.Format( "{0} {1}, {2} {3} {4}, {5}",
                  address.HouseNumber,
                  address.Street,
                  address.City,
                  address.State,
                  address.PostalCode,
                  address.Country ).Trim() );
                }
            }

        if ( Addresses.Count > 0 )
            {
            Address = Addresses[ 0 ].ToString();
            }
        else
            {
            Address = "";
            }

        done.Set();
        Completed = true;
        }
    }

public static class CoordinateConverter
    {
    public static GeoCoordinate ConvertGeocoordinate( Geocoordinate geocoordinate )
        {
        return new GeoCoordinate
            (
            geocoordinate.Latitude,
            geocoordinate.Longitude,
            geocoordinate.Altitude ?? Double.NaN,
            geocoordinate.Accuracy,
            geocoordinate.AltitudeAccuracy ?? Double.NaN,
            geocoordinate.Speed ?? Double.NaN,
            geocoordinate.Heading ?? Double.NaN
            );
        }

    public static async Task<GeoCoordinate> GetLocation()
        {
        // Get current location.
        Geolocator myGeolocator = new Geolocator();
        myGeolocator.DesiredAccuracy = PositionAccuracy.High;
        //myGeolocator.DesiredAccuracyInMeters = 50;

        Geocoordinate myGeocoordinate = null;

        try
            {
            Geoposition myGeoposition = await myGeolocator.GetGeopositionAsync
                    (
                    maximumAge: TimeSpan.FromMinutes( 1 ),
                    timeout: TimeSpan.FromSeconds( 10 )
                    );
            myGeocoordinate = myGeoposition.Coordinate;
            }
        catch ( Exception ex )
            {
            if ( (uint)ex.HResult == 0x80004004 )
                {
                // the application does not have the right capability or the location master switch is off
                MessageBox.Show( "location  is disabled in phone settings" );
                }
            }

        if ( myGeocoordinate == null )
            {
            return GeoCoordinate.Unknown;
            }

        GeoCoordinate myGeoCoordinate = CoordinateConverter.ConvertGeocoordinate( myGeocoordinate );
        return myGeoCoordinate;
        }
    }
}

代码工作正常,即调用 ReverseGeocodeQueryCompleted 并且正确计算地址.但是,ReverseGeocodeQueryCompleted 发生在 GetLocation() 完成并且分配给 Address 的地址为空之后.

The code works fine, i.e. the ReverseGeocodeQueryCompleted is called and the address is being calculated properly. However, ReverseGeocodeQueryCompleted occurs after GetLocation() is completed and the address assigned to Address is null.

我的问题是如何制作

ReverseGeoCoding.StartReverseGeoCoding( Location );

等待完成:

ReverseGeocodeQueryCompleted( object sender, QueryCompletedEventArgs<System.Collections.Generic.IList<MapLocation>> e )
{
....
}

我尝试使用 AutoResetEventWaitOne,但整个线程停止并且代码永远不会到达 ReverseGeocodeQueryCompleted().

I tried with AutoResetEvent and WaitOne, but the whole thread stops and the code never gets to ReverseGeocodeQueryCompleted().

我愿意接受如何解决这个问题的建议.

I am open to suggestions how to solve this problem.

EitanB

推荐答案

这是一个能够等待 QueryAsync 的扩展方法:

Here is an extension method to be Able to await QueryAsync:

public static Task<IList<MapLocation>> QueryTaskAsync(this ReverseGeocodeQuery reverseGeocode)
{
    TaskCompletionSource<IList<MapLocation> > tcs = new TaskCompletionSource<IList<MapLocation>>();
    EventHandler<QueryCompletedEventArgs<IList<MapLocation>>> queryCompleted = null;

    queryCompleted = (send, arg) =>
        {
            // Unregister event so that QueryTaskAsync can be called several time on same object
            reverseGeocode.QueryCompleted -= queryCompleted;

            if (arg.Error != null)
            {
                tcs.SetException(arg.Error);
            }
            else if (arg.Cancelled)
            {
                tcs.SetCanceled();
            }
            else
            {
                tcs.SetResult(arg.Result);
            }
        };

        reverseGeocode.QueryCompleted += queryCompleted;

        reverseGeocode.QueryAsync();

        return tcs.Task;
    }

这篇关于如何等待 QueryCompleted 事件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-04 07:40