上方廣告

2012年2月23日 星期四

Windows Phone 7 取得GPS訊號

要取得GPS的訊號主要是透過GeoCoordinateWatche來取得,下面的範例是一個簡單的取得經緯度的語法。

GeoCoordinateWatcher geowatcher = new GeoCoordinateWatcher();
//嘗試取得資料,若超過指定的時間取不到就會回傳False
geowatcher.TryStart(false, TimeSpan.FromMilliseconds(1000));
GeoCoordinate coord = geowatcher.Position.Location;

if (coord.IsUnknown != true)
{
    MessageBox.Show(
        "Latitude : " + coord.Latitude.ToString() + Environment.NewLine +
        "Longitude : " + coord.Longitude.ToString()
    );
}
 


以上這種方式呼叫一次只會取得一次並不會繼續監聽GPS的訊號,但是如果我們是要寫GPS定位程式這樣的結果就不是我們想要的,我們需要的是能自動判斷GPS的訊號是否有改變。因此我們需要使用下面的方式來進行。建議使用低精準度(因愈高精準度需要更多的電力來收集資料)、低耗電與電力最佳化的目標,詳細說明可參閱MSDN
// Current status of the location service
GeoPositionStatus currentState = GeoPositionStatus.Initializing;
// Use this class to access Windows Phone location service
GeoCoordinateWatcher geoWatcher;
// Current geo-location
private GeoPosition currentGeoCoord = null;

GeoPosition CurrentGeoCoord
{
    get
    {
        return currentGeoCoord;
    }
    set
    {
        currentGeoCoord = value;
    }
}

// 建構函式
public MainPage()
{
 geoWatcher = new GeoCoordinateWatcher(GeoPositionAccuracy.Default);
 geoWatcher.StatusChanged += new EventHandler(geoWatcher_StatusChanged);
 geoWatcher.PositionChanged += new EventHandler>(geoWatcher_PositionChanged);
 geoWatcher.MovementThreshold = 0.5;
 geoWatcher.Start();
}

//位置服務狀態變更時
void geoWatcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e)
{
    currentState = e.Status;

    switch (e.Status)
    {
        case GeoPositionStatus.Disabled:
            if (geoWatcher.Permission == GeoPositionPermission.Denied)
            {
                MessageBox.Show("Please turn on geo-location service in the settings tab.");
            }
            else if (geoWatcher.Permission == GeoPositionPermission.Granted)
            {
                MessageBox.Show("Your device doesn't support geo-location service.");
            }
            break;
        case GeoPositionStatus.Ready:
            CurrentGeoCoord = geoWatcher.Position;
            break;
    }
}

//位置服務偵測到位置改變時
void geoWatcher_PositionChanged(object sender, GeoPositionChangedEventArgs e)
{
    if (currentState == GeoPositionStatus.Ready)
    {
        CurrentGeoCoord = e.Position;
    }
}

上面的圖示所顯示的經緯度是在模擬器上面執行的,但是我發現該經緯度並不是我目前所在的位置,直覺告訴我應該是跟Andorid和iPhone一樣,模擬器無法找到正確的座標資訊,Google了一下,找到了模擬器的測試方式,如欲知詳情請參閱MSDN,以下語法就說明一下根據MSDN調整的方式。

1. 在Visual Studio的專案加入以下三個參考,"System.Device", "Microsoft.Phone.Reactive", "System.Observable"。


2. 在程式開頭加入以下語法
    using System.Device.Location;
    using Microsoft.Phone.Reactive;
    using System.Threading;
//Debug Mode
#if (DEBUG)
        bool useEmulation = true;
#else
        bool useEmulation = false;
#endif

// 建構函式
public MainPage()
{
    //使用Debug Mode
    if (!useEmulation)
    {
        geoWatcher = new GeoCoordinateWatcher(GeoPositionAccuracy.Default);
        geoWatcher.StatusChanged += new EventHandler(geoWatcher_StatusChanged);
        geoWatcher.PositionChanged += new EventHandler>(geoWatcher_PositionChanged);
        geoWatcher.MovementThreshold = 0.5;
        geoWatcher.Start();
    }
    else
    {
        // Start the thread on which emulated location data is generated.
        // The method StartEmulation is defined next.
        Thread emulationThread = new Thread(StartEmulation);
        emulationThread.Start();
    }
}

private void StartEmulation()
{
    // EmulatePositionChangedEvents returns an IEnumerable object.
    // Convert this to an Observable sequence.
    var position = EmulatePositionChangedEvents().ToObservable();

    // Subscribe to the Observable sequence.
    // Use null for the sender parameter to the event handler.
    position.Subscribe(evt => geoWatcher_PositionChanged(null, evt));
}

static double _latitude = 22.607090306469686;
static double _longitude = 120.3134036064148;

static IEnumerable> EmulatePositionChangedEvents()
{
    // Create a Random object to create random numbers.
    Random random = new Random();

    // Loop infinitely.
    for (; ; )
    {
        // Pause for 100 milliseconds in each loop.
        Thread.Sleep(random.Next(100));

        _latitude += 0.0001;
        _longitude += 0.0001;

        // Use yield to return a new instance of the GeoPositionChangedEventArgs class that is exposed
        // through the IEnumerable interface.
        yield return new GeoPositionChangedEventArgs(
            new GeoPosition(DateTimeOffset.Now, new GeoCoordinate(_latitude, _longitude)));
    }
}


下圖就是完成的樣子,理論上用Debug Mode來看GoogleMap就會一直往東北方移動。