.NET 4.0 New Feature - System.Device.Location

.NET 4.0 New Feature - System.Device.Location

.NET 4.0 BCL中新增了System.Device.Location命名空間,該命名空間內提供許多類別允許應用程式開發人員在Windows 7以後的作業系統使用單一 API 輕鬆存取裝置位置,開發人員不需去考量電腦中可以使用的位置提供者,也不需要為多個位置提供者排定彼此的優先權與中間的轉換,透過這個命名空間開發人員可以更專注於位置取得程式的撰寫,而不需花費心思考量各式各樣的位置提供者。

 

在使用System.Device.Location命名空間前,我們必須知道裝置位置的資訊是由位置提供者提供的,位置提供者的位置資訊可能是由GPS,或是由IP位置去查詢,甚至是用Wifi、手機基地台的訊號做三角定位取得,在Windows 7中我們可透過控制台中的Location and Other Sensors設定位置提供者。

image

 

若在作業系統安裝完後沒設定過的話,開啟時應該是像下面一樣是沒有Sensor的

image

 

左下角有個"Default Location"連結可供設定預設位置提供者的位置資訊,當裝置中未安裝有位置提供者時,會嚐試由預設位置取得位置資訊。

  image

 

若沒設定預設位置提供者的位置資訊,且在沒有其它位置提供者的環境下試圖運行程式取得裝置位置,則會彈出"Enter a default location"對話框請求設定預設位置提供者的位置資訊。

image

 

預設位置的設定能在沒位置提供者的狀態下提供位置資訊,但這樣的位置資訊一定是不準的,也無法自動偵測到當前的位置資訊,想要自動提供正確的位置資訊還是必須藉由位置提供者的幫助,若在裝置中沒有GPS這類精準度較高的位置提供者,我們可以透過安裝GeoSense For Windows來由無線網路去做粗略的定位。

image

image

image

image

 

安裝完後我們可在"Location and Other Sensors"看到會新增一個Geosense Location Sensor,這邊記得要把它啟動後套用(不是開發用也可以安裝,有些應用程式會依此資訊提供在地化服務)。

image

 

設定完位置提供者後,在開始使用System.Device.Location前,我們還必須要將System.Device.dll加入專案參考。

image

 

System.Device.Location命名空間內含有GeoCoordinateWatcher、GeoCoordinate 、CivicAddressResolver、與CivicAddress這幾個比較重要的類別。下面是摘錄自MSDN上的說明:

Name Description
GeoCoordinateWatcher 提供以經度和緯度座標為基礎的位置資料
GeoCoordinate 表示緯度與經度座標所決定的地理位置。 這個值也可能包含高度、精確度、速度和路線等資訊
CivicAddressResolver 提供能夠從座標位置解析實體位址的功能
CivicAddress 表示實體地址。 實體地址可以包含如街道地址、郵遞區號、省份及國家或地區等欄位

 

GeoCoordinateWatcher類別可主動提供從位置提供者那邊取得的裝置位置資訊,也可以設定想要的定位精準度與位置變更的通知頻率;GeoCoordinate類別可取得裝置所在的經度、緯度、高度,與其速度與路線等資訊,也可以計算兩個裝置位置間的距離;CivicAddressResolver能將GeoCoordinate型態的經緯度位置資訊轉換為CivicAddress型態的實體位置資訊;CivicAddress類別為實體位置資訊,提供街道地址、郵遞區號、省份及國家或地區等真實地址。

 

使用上我們需要先建立GeoCoordinateWatcher類別的物件實體,呼叫Start或是TryStart開始截取GeoCoordinate型態的位置資訊,若進一步需要實體位置資訊,可再建立CivicAddressResolver物件實體,將從GeoCoordinateWatcher取得的GeoCoordinate帶入ResolveAddress或是ResolveAddressAsync方法以取得CivicAddress物件。

 

實際來看個使用範例:

            {
                watcher.MovementThreshold = 1.0;
                watcher.TryStart(false, TimeSpan.FromMilliseconds(1000));

                GeoCoordinate location = watcher.Position.Location;
                if (location.IsUnknown)
                    return;

                Console.WriteLine("Time: {0}", e.Position.Timestamp);
                Console.WriteLine("Longitude: {0}", location.Longitude);    //經度
                Console.WriteLine("Latitude: {0}", location.Latitude);      //緯度
                Console.WriteLine("Altitude: {0}", location.Altitude);      //高度
                Console.WriteLine("Course: {0}", location.Course);          //角度
                Console.WriteLine("Speed: {0}", location.Speed);            //速度


                CivicAddressResolver resolver = new CivicAddressResolver();
                CivicAddress realLocation = m_addressResolver.ResolveAddress(location);

                if (realLocation.IsUnknown)
                    return;

                Console.WriteLine("Address1: {0}", realLocation.AddressLine1);          //實際地址
                Console.WriteLine("Address2: {0}", realLocation.AddressLine2);
                Console.WriteLine("Building: {0}", realLocation.Building);              //門牌號碼
                Console.WriteLine("City: {0}", realLocation.City);                      //縣市
                Console.WriteLine("CountryRegion: {0}", realLocation.CountryRegion);    //國家
                Console.WriteLine("PostalCode: {0}", realLocation.PostalCode);          //郵遞區號
                Console.WriteLine("StateProvince: {0}", realLocation.StateProvince);    //省份
                Console.WriteLine("FloorLevel: {0}", realLocation.FloorLevel);          //樓層
            }

這邊示範的是使用GeoCoordinateWatcher.TryStart方法同步截取位置資訊,若需非同步去截取位置資訊可如下採用GeoCoordinateWatcher.Start搭配事件的方式處理:

        {
            using (GeoCoordinateWatcher watch = new GeoCoordinateWatcher())
            {
                watch.Start();
                watch.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watch_PositionChanged);
                Console.Read();
            }
        }

        static CivicAddressResolver m_addressResolver = new CivicAddressResolver();
        static void watch_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            var location = e.Position.Location;
            Console.WriteLine("Time: {0}", e.Position.Timestamp);
            Console.WriteLine("Longitude: {0}", location.Longitude);    //經度
            Console.WriteLine("Latitude: {0}", location.Latitude);      //緯度
            Console.WriteLine("Altitude: {0}", location.Altitude);      //高度
            Console.WriteLine("Course: {0}", location.Course);          //角度
            Console.WriteLine("Speed: {0}", location.Speed);            //速度

            var realLocation = m_addressResolver.ResolveAddress(location);
            Console.WriteLine("Address1: {0}", realLocation.AddressLine1);          //實際地址
            Console.WriteLine("Address2: {0}", realLocation.AddressLine2);
            Console.WriteLine("Building: {0}", realLocation.Building);              //門牌號碼
            Console.WriteLine("City: {0}", realLocation.City);                      //縣市
            Console.WriteLine("CountryRegion: {0}", realLocation.CountryRegion);    //國家
            Console.WriteLine("PostalCode: {0}", realLocation.PostalCode);          //郵遞區號
            Console.WriteLine("StateProvince: {0}", realLocation.StateProvince);    //省份
            Console.WriteLine("FloorLevel: {0}", realLocation.FloorLevel);          //樓層

            Console.WriteLine();
        }

 

要特別注意的是,System.Device.Location命名空間的裝置定位機制只支援Windows 7以後的作業系統版本,因為只有Windows 7以後的作業系統有得設定位置提供者,在 Windows 7之前的 Windows 版本,雖然仍然可以建立System.Device.Location命名空間內的GeoCoordinateWatcher物件,但 Status 屬性會是 Disabled,Position 之 Location 屬性也會是 Unknown,而且不會引發位置變更的事件,簡單的說就是不能使用。

 

Link