共用方式為


Windows Phone

Windows Phone 寫一個指南針應用程式

Donn Morse

下載代碼示例

作為為 Windows 8 的感應器平臺文檔的 writerresponsible,我想看到許多開發人員盡可能採用我們新的平臺。 而且,因為地鐵樣式應用程式可以使用 XAML 和 C# 編寫,Windows Phone 開發商是理想的候選人,為此遷移。 Windows Phone 開發商已經有實驗­與 XAML 中,rience 和數量也有經驗與感應器 (因為公開加速度計、 指南針、 陀螺儀和 GPS 感應器中的最新的 Windows Phone 版本)。

為説明我更好地瞭解 Windows Phone 開發人員和他們的開發平臺,決定要寫一個簡單的羅盤應用去年秋天。 一旦我寫的我提交使用 App 集線器的 Windows Phone 市場的免費版本。 自接受,這款應用程式已下載由 Windows Phone 使用者從遠至瑞士和馬來西亞。

本文介紹的應用程式的開發。

指南針應用程式

羅盤應用程式使用的指南針或磁強計,內置到 Windows Phone 的設備。 這個應用程式提供了對真正的北方的標題,以及互惠的標題,當在船上或在一個偏遠的地區,用一張地圖中的定向越野航行時很有用。 此外,這款應用程式允許使用者之間進行切換時 (例如,"090"度) 的數位標題到 Alpha 的標題 (例如,"E"東)。 這款應用程式還允許使用者鎖定當前標題。 當使用者需要要保持靜止,以便他們可以採取軸承上地圖或圖表上的特定里程碑或參考點的指標時,這非常有用。

圖 1 顯示三星焦點上運行的應用程式。 左邊的圖像顯示數值的標題和右邊的圖像顯示 Alpha 的標題。

The Running App, Showing a Numeric Heading (Left) and an Alpha Heading (Right)
圖 1 顯示標題 (左) 的數位和字母標題 (右) 的應用程式運行

設計使用者介面

作為開發人員習慣于為 PC 編寫的應用程式,最初覺得有限通過減少的螢幕房地產的電話。 然而,這並不是極高。 只是需要給予更多的思想 — — 和審慎考慮 — — 給我新的螢幕尺寸方面的應用程式中的功能。 我羅盤的應用程式有兩個螢幕: 校準螢幕和主導航螢幕。

校準螢幕的指南針或磁強計、 Windows Phone 設備上安裝需要校準後設備通電。 此外,這些感應器可能需要定期重新校準。 為了説明您以程式設計方式檢測需要進行校正時,該平臺支援一種 HeadingAccuracy 屬性,您可以使用來檢測當前校準。 此外,該平臺支援校準激發事件的如果指南針需要校準。

我的應用程式處理該校準事件,這樣,反過來,顯示一個提示使用者手動校準設備通過掃描在電話中一圖 8 項議案的校準螢幕 (calibrationStackPanel)。 隨著使用者席捲手機,當前的精度顯示在用紅色字體 CalibrationTextBlock 直至取得所需的準確性,如中所示圖 2。 一旦返回的準確性是小於或等於 10 °,數位值將被清除並"完成 !",綠色的出現。

The Calibration Screen
圖 2 在校準螢幕

相應的代碼,它支援標定發現在 compass_Current 中的模組 MainPage.xaml.cs­ValueChanged 事件處理常式,如中所示圖 3

圖 3 標定指南針

...
else
{
 if (HeadingAccuracy <= 10)
 {
  CalibrationTextBlock.Foreground = 
    new SolidColorBrush(Colors.Green);
  CalibrationTextBlock.Text = "Complete!";
 }
 else
 {
  CalibrationTextBlock.Foreground = 
    new SolidColorBrush(Colors.Red);
  CalibrationTextBlock.Text = 
    HeadingAccuracy.ToString("0.0");
 }
}

一旦取得了所需的精度,被提示使用者按下完成按鈕,它隱藏在校準螢幕並顯示應用程式的主畫面。

在主畫面此螢幕顯示一個數位或字母標題和互惠的值。 此外,它呈現了面向對真正的北方的羅盤的臉。 最後,讓使用者能夠改變作為輸出,主畫面顯示四個控制項 (或按鈕) 以及鎖的標題值和羅盤的臉。

圖 4 顯示我的應用程式的主畫面上,MainPage.xaml,因為它在 Visual Studio 中出現。

The App’s Primary Screen in Visual Studio
圖 4 應用程式的主畫面在 Visual Studio 中

在主畫面中的 UI 元素的大多數是簡單 TextBlock 和按鈕控制項。 文字區塊標識標題和其互惠的值。 按鈕使使用者能夠控制輸出。 然而,有點更多地參與的羅盤的臉。

指南針臉的羅盤的臉由三個元件組成: 背景圖像、 前景圖像和一個較大、 接壤的橢圓,在其中的前景色和背景圖像旋轉。 背景圖像包含一個羅盤、 一條水平線和垂直線上的四個點所對應的字母。 前景圖像創建熏玻璃效果。

背景圖像在 XAML 中,背景圖像被命名為的 CompassFace (稍後在旋轉的羅盤的臉的代碼中引用此變數的名稱):

<Image Height="263" HorizontalAlignment="Left" Margin="91,266,0,0"
  Name="CompassFace" VerticalAlignment="Top" Width="263"  
  Source="/Compass71;component/compass.png" Stretch="None" />

前景圖像**的羅盤的臉,EllipseGlass,前景在本身的 XAML 中定義。**熏玻璃效果使用線性漸層畫筆進行創建的。 我創建了使用 Microsoft 表達混合 4 此橢圓。 表達混合工具相容 Visual Studio,並允許您載入您的應用程式的 XAML 和增強使用者介面的自訂圖形。 圖 5 Expression Blend 顯示編輯器,它出現時創建的著色的橢圓。

Creating a Shaded Ellipse in Expression Blend
圖 5 中表達混合創建一個帶陰影的橢圓

我完成表達混合中的橢圓的編輯後,在我的 Visual Studio 專案 XAML 已更新與下面的 XML:

<Ellipse Height="263"  Width="263" x:Name="EllipseGlass" 
  Margin="91,266,102,239" Stroke="Black" StrokeThickness="1">
  <Ellipse.Fill>
    <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
    <GradientStop Color="#A5000000" Offset="0" />
    <GradientStop Color="#BFFFFFFF" Offset="1" />
    </LinearGradientBrush>
  </Ellipse.Fill>

請注意 EllipseGlass (263 x 263 圖元) 的尺寸是 compass.png 的尺寸精確匹配。 此外注意到該物件名稱,EllipseGlass,引用稍後在代碼中執行旋轉的羅盤的臉。

指南針的臉邊境在一個更大、 白色的橢圓,帶有紅色邊框內旋轉羅盤的臉。 此橢圓的 XAML 中定義,命名為 EllipseBorder:

<Ellipse Height="385" HorizontalAlignment="Left" Margin="31,0,0,176"
  Name="EllipseBorder" Stroke="#FFF80D0D" StrokeThickness="2"
  VerticalAlignment="Bottom" Width="385" Fill="White" />

隱藏使用者介面代碼

代碼駐留在檔 MainPage.xaml.cs 中附帶的代碼下載,和它訪問所需的應用程式的命名空間、 初始化感應器、 設置報告的時間間隔和處理應用程式的各種功能: 校準、 旋轉羅盤的臉,數位和字母輸出等之間切換。

訪問您的代碼中的羅盤寫一個羅盤的應用程式 (或任何應用程式訪問電話感應器之一) 的第一步是以獲取公開的 Microsoft.Devices.Sensors 的命名空間的感應器物件的訪問。 這通過下列操作在 MainPage.xaml.cs 中使用指令:

using Microsoft.Devices.Sensors;

一次這個使用指令出現在檔中,可以創建一個羅盤的變數,給我的程式設計訪問在電話中實際的設備:

namespace Compass71
{
  public partial class MainPage : PhoneApplicationPage
  {
    Compass compass = new Compass();

我將使用此變數來啟動指南針,停止它,檢索當前的航向精度,設置報告的時間間隔,等等。

啟動指南針和設置報告頻率一旦創建的羅盤的變數,可以調用的方法和物件上的設置屬性。 我所調用的第一個方法是開始的方法,它允許我首先從感應器接收資料。 我開始指南針後,設置報告的時間間隔 — — 感應器的更新之間的時間 — — 為 400 毫秒 (請注意 TimeBetweenUpdates 屬性,需要 20 ms 的倍數):

compass.TimeBetweenUpdates = 
  TimeSpan.FromMilliseconds(400);  // Must be multiple of 20
compass.Start();

選擇 400 毫秒值是由試驗和錯誤。 預設的報告間隔是極短。 如果您嘗試運行該應用程式在此預設值,所以經常旋轉羅盤的臉似乎是不穩定。

建立羅盤的事件處理常式羅盤的應用程式支援兩個事件處理常式: 之一,顯示校準頁 (校準­StackPanel),和另一種呈現當前標題和旋轉的羅盤的臉。

定義並建立校準的事件處理常式的校準事件處理常式包含相對較少的程式碼。 此代碼中所示圖 6,完成了兩個主要任務: 第一,它顯示的在 MainPage.xaml 檔中定義的校準螢幕 第二,它將設置為 true 的布林變數校準。

圖 6 校準的事件處理常式

void compass_Calibrate(object sender, 
  CalibrationEventArgs e)
{
  try
  {
    Dispatcher.BeginInvoke(() => 
    { calibrationStackPanel.Visibility =
      Visibility.Visible; 
    });
    calibrating = true;
  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.Message.ToString(), 
       "Error!", MessageBoxButton.OK);
  }
}

因為從後臺執行緒調用此事件處理常式,它沒有直接存取到 UI 執行緒。 所以,若要顯示校準螢幕,我需要在調度員物件上調用 BeginInvoke 方法。

布林變數校準值更改事件處理常式 (compass_CurrentValueChanged) 檢查代碼中。 當此變數是真的時,我忽略了羅盤,並使用校準的最新資料更新校準螢幕。 當變數是虛假的時我更新羅盤讀數,並執行輪換的羅盤的臉。

此事件處理常式被建立與下面的程式碼的網頁建構函式中:

compass.Calibrate += new EventHandler<CalibrationEventArgs>(compass_Calibrate);

定義並建立 Value-Changed 處理常式 (compass_CurrentValueChanged) 的值更改事件處理常式調用從指南針到達的一種新的閱讀每個時間。 根據的校準狀態變數,它要麼更新校準螢幕或它更新主畫面。

它更新時的主畫面,該事件處理常式將執行以下任務:

  • 它計算的真實和互惠的標題,對真正的北方。
  • 它旋轉的羅盤的臉。
  • 它將呈現當前和對等標題。

計算標題下面的代碼演示如何的事件處理常式檢索真北的 SensorReading 物件上使用 TrueHeading 屬性的標題:

 

TrueHeading = e.SensorReading.TrueHeading;
  if ((180 <= TrueHeading) && (TrueHeading <= 360))
    ReciprocalHeading = TrueHeading - 180;
  Else
    ReciprocalHeading = TrueHeading + 180;

圖 7 演示的事件處理常式如何更新當前和對等標題。

圖 7 更新當前和互惠的標題

if (!Alphabetic) // Render numeric heading
{
  HeadingTextBlock.Text = TrueHeading.ToString();
  RecipTextBlock.Text = ReciprocalHeading.ToString();
}
else // Render alpha heading
{
  if (((337 <= TrueHeading) && (TrueHeading < 360)) ||
    ((0 <= TrueHeading) && (TrueHeading < 22)))
  {
    HeadingTextBlock.Text = "N";
    RecipTextBlock.Text = "S";
  }
  else if ((22 <= TrueHeading) && (TrueHeading < 67))
  {
    HeadingTextBlock.Text = "NE";
    RecipTextBlock.Text = "SW";
  }
  else if ((67 <= TrueHeading) && (TrueHeading < 112))
  {
    HeadingTextBlock.Text = "E";
    RecipTextBlock.Text = "W";
  }
  else if ((112 <= TrueHeading) && (TrueHeading < 152))
  {
    HeadingTextBlock.Text = "SE";
    RecipTextBlock.Text = "NW";
  }
  else if ((152 <= TrueHeading) && (TrueHeading < 202))
  {
    HeadingTextBlock.Text = "S";
    RecipTextBlock.Text = "N";
  }
  else if ((202 <= TrueHeading) && (TrueHeading < 247))
  {
    HeadingTextBlock.Text = "SW";
    RecipTextBlock.Text = "NE";
  }
  else if ((247 <= TrueHeading) && (TrueHeading < 292))
  {
    HeadingTextBlock.Text = "W";
    RecipTextBlock.Text = "E";
  }
  else if ((292 <= TrueHeading) && (TrueHeading < 337))
  {
    HeadingTextBlock.Text = "NW";
    RecipTextBlock.Text = "SE";
  }
}

旋轉羅盤臉下面的程式碼片段演示了這款應用程式如何旋轉這兩個橢圓構成的背景與前景的羅盤的臉:

CompassFace.RenderTransformOrigin = new Point(0.5, 0.5);
EllipseGlass.RenderTransformOrigin = new Point(0.5, 0.5);
transform.Angle = 360 - TrueHeading;
CompassFace.RenderTransform = transform;
EllipseGlass.RenderTransform = transform;

變數 CompassFace 對應于包含指南針 (N、 E、 W 和 S) 和橫向和縱向線的四個點的背景圖像。 變數 EllipseGlass 對應的熏玻璃圖層。

我可以應用旋轉變換之前,我需要確保變換居中的我會旋轉的兩個物件。 這是通過調用 RenderTransformOrigin 方法對每個物件和供應的座標 (0.5、 0.5)。 (有關此方法和其使用有關的詳細資訊,請參閱 MSDN 庫頁,"UIElement.RenderTransformOrigin 財產,"在 bit.ly/KIn8Zh。)

一旦我已經為中心轉變,我可以計算角度和執行旋轉。 我計算角度減去從 360 當前標題。 (這是我剛收到的事件處理常式中的標題)。我申請了這個新角度的變換器屬性。

鎖定和解鎖指南針的鎖定和解鎖­ing 功能用於室外人使用應用程式導航 (無論是在一條船或手遠足徑用地圖上)。 此功能很簡單 ; 它調用 Stop 方法的指南針來鎖定在標題上,然後它調用 Start 方法恢復標題檢索。

當使用者按下 LockButton 時調用 Stop 方法:

private void LockButton_Click(object sender, 
  RoutedEventArgs e)
{
  try
  {
    compass.Stop();
  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.Message.ToString(), 
      "Error!", MessageBoxButton.OK);
  }
}

當使用者按下 UnlockButton 時調用 Start 方法:

private void UnlockButton_Click(object sender, 
  RoutedEventArgs e)
{
  try
  {
    compass.Start();
    compass.TimeBetweenUpdates =
      TimeSpan.FromMilliseconds(400);  
      // Must be multiple of 20
  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.Message.ToString(), 
      "Error!", MessageBoxButton.OK);
  }
}

請注意除了重新開機指南針,重定的報告間隔到 400 ms,以確保一致的行為。

Toggling 之間數位和字母標題的字母和數位的標題之間切換的代碼由單個布林變數命名為 Alphabetic 時,如果使用者按 AlphaButton 或 NumericButton 設置的控制。 當使用者按下 AlphaButton 時,此變數被設置為 True ; 當使用者按下 NumericButton,系統會將它設置為 False。

以下是 AlphaButton 按一下事件的代碼:

private void AlphaButton_Click(
    object sender, RoutedEventArgs e)
  {
    try
    {
      Alphabetic = true;
    }
    catch (Exception ex)
    {
      MessageBox.Show(
         ex.Message.ToString(), "Error!",
        MessageBoxButton.OK);
    }
  }

在 compass_CurrentValueChanged 事件處理常式代碼檢查 Alphabetic 以確定它是否應該呈現的數位或字母的標題。

支援的光與暗的可見度主題創建應用程式,並提交它的 App 集線器的認證後,我非常驚訝地接收它已失敗,因為某些使用者介面元素不見光的可見度主題測試時的通知。 (我一直只與黑暗主題,失敗了,測試光主題。

若要解決此問題,我的網頁建構函式,它檢索當前主題,然後設置的使用者介面元素 (文字區塊和按鈕),為給定的主題工作的前景顏色添加代碼。 如果光主題設置,元素的前景顏色設置為黑色和紅色。 如果設置了黑暗的主題,則元素的前景顏色設置為黑暗與光明的灰色。 圖 8 顯示此代碼。

圖 8 協調主題和顏色

Visibility isLight = (Visibility)Resources["PhoneLightThemeVisibility"]; // For light theme
if (isLight == System.Windows.Visibility.Visible) // Light theme enabled
{
  // Constructor technique
  SolidColorBrush scb = new SolidColorBrush(Colors.Black);
  SolidColorBrush scb2 = new SolidColorBrush(Colors.Red);
  RecipLabelTextBlock.Foreground = scb;
  HeadingLabelTextBlock.Foreground = scb;
  RecipTextBlock.Foreground = scb2;
  HeadingTextBlock.Foreground = scb2;
  LockButton.Foreground = scb;
  UnlockButton.Foreground = scb;
  AlphaButton.Foreground = scb;
  NumericButton.Foreground = scb;
}
else // Dark color scheme is selected—set text colors accordingly
{
  // Constructor technique
  SolidColorBrush scb = new SolidColorBrush(Colors.DarkGray);
  SolidColorBrush scb2 = new SolidColorBrush(Colors.LightGray);
  RecipLabelTextBlock.Foreground = scb;
  HeadingLabelTextBlock.Foreground = scb;
  RecipTextBlock.Foreground = scb2;
  HeadingTextBlock.Foreground = scb2;
  LockButton.Foreground = scb;
  UnlockButton.Foreground = scb;
  AlphaButton.Foreground = scb;
  NumericButton.Foreground = scb;
}

樂趣和有價值的

此應用程式的創建是有很多樂趣,和它也有價值。 曾經在 Windows Phone 平臺上的感應器,現在我更清楚地瞭解這一平臺和感應器支援之間在 Windows 8 的差異。 但我感觸最大的相似之處。 我的預感是如果你是 Windows Phone 的開發人員花了與感應器的命名空間的任何時間,你去找遷移到 Windows 8 極其簡單。 而且,在 Windows 8,你會發現其他感應器測斜儀、 定位感應器和簡單定位感應器等。 (方向感應器是多個感應器,它返回一個四元數或您可以使用來控制複雜的遊戲的旋轉矩陣的融合。 簡單定位感應器可以檢測到您的設備是否在縱向或橫向模式中,以及仰面朝下。)

所有這些感應器所帶來的發展機遇是令人興奮和期待看到我們創造性的開發人員社區可以運用他們的想像力的方式。

Donn Morse 是一個高級程式設計作家在微軟 Windows 團隊在過去的幾年一直致力於感應器平臺,從到驅動程式的應用方面。他是激情,和著迷感應器和它們的使用。

由於有關檢討這篇文章是以下技術專家: Jason Scott