Il presente articolo è stato tradotto automaticamente.

Windows Phone

Scrittura di un'applicazione bussola per Windows Phone

Donn Morse

Scarica il codice di esempio

Come un writerresponsible per la documentazione di platform sensore per Windows 8, voglio vedere come molti sviluppatori possibile adottano la nostra nuova piattaforma.E, perché lo stile Metro apps può essere scritto utilizzando XAML e c#, lo sviluppatore di Windows Phone è un candidato ideale per questa migrazione.Gli sviluppatori di Windows Phone hanno già expe­rience con XAML e un numero anche avere esperienza con i sensori (perché l'accelerometro, bussola, giroscopio e sensori GPS sono esposti nella più recente versione Windows Phone).

Per aiutarmi a capire meglio gli sviluppatori Windows Phone e la loro piattaforma di sviluppo, ho deciso di scrivere una semplice applicazione bussola lo scorso autunno.Una volta che l'ho scritto, ho presentato una versione gratuita per il mercato di Windows Phone usando l'App Hub.Dall'accettazione, l'app è stato scaricato dagli utenti di Windows Phone da lontano come la Svizzera e la Malesia.

Questo articolo riguarda lo sviluppo dell'applicazione.

L'applicazione bussola

L'applicazione bussola utilizza la bussola, o magnetometro, costruito al dispositivo Windows Phone.Questa applicazione fornisce una direzione rispetto al Nord vero, come pure una voce reciproca che può essere utile quando si naviga in una barca o orienteering in una zona remota con una mappa.Inoltre, l'applicazione consente all'utente di passare da un'intestazione numerica (ad esempio, "090" gradi) una voce alfa (ad esempio, "E" per est).L'app consente inoltre all'utente di bloccare la direzione attuale.Questo è utile quando gli utenti hanno bisogno del puntatore a rimanere fermo così essi possono prendere un cuscinetto su un punto specifico di riferimento o reference su una mappa o un grafico.

Figura 1 Mostra l'applicazione in esecuzione su un Samsung Focus.L'immagine sulla sinistra mostra una rubrica numerica e l'immagine sulla destra viene visualizzata una voce alfa.

The Running App, Showing a Numeric Heading (Left) and an Alpha Heading (Right)Figura 1 l'esecuzione App, mostrando un numerico rubrica (a sinistra) e un'Alfa voce (a destra)

Progettazione dell'interfaccia utente

Come sviluppatore abituato alla scrittura di applicazioni per il PC, mi sentivo inizialmente limitata da immobiliare schermo ridotto sul telefono.Tuttavia, questo non era un showstopper.Ho solo bisogno di dare un po ' più pensiero — e attenta considerazione — le caratteristiche nel mio app per quanto riguarda le nuove dimensioni dello schermo.Il mio app bussola ha due schermi: uno schermo di calibrazione e la schermata di navigazione principale.

La schermata di calibrazione la bussola, o magnetometro, installato su un dispositivo di Windows Phone richiede calibrazione dopo che il dispositivo è acceso.Inoltre, questi sensori potrebbero richiedere la ritaratura periodica.Per aiutarvi a individuare a livello di programmazione quando la calibrazione è necessaria, la piattaforma supporta una proprietà HeadingAccuracy che è possibile utilizzare per rilevare la taratura corrente.Inoltre, la piattaforma supporta un evento Calibrate che viene generato se la bussola richiede calibrazione.

Il mio app gestisce l'evento Calibrate, che, a sua volta, viene visualizzata una schermata di calibrazione (calibrationStackPanel) che richiede all'utente di calibrare manualmente il dispositivo da spazzare il telefono in un movimento di figura 8.Come l'utente spazza il telefono, la precisione corrente viene visualizzata in CalibrationTextBlock con un carattere di colore rosso fino a raggiungere la precisione voluta, come mostrato Figura 2.Una volta che la precisione restituita è minore o uguale a 10 °, i valori numerici vengono cancellati e compare un verde "Complete!".

The Calibration ScreenFigura 2 la schermata di calibrazione

Il codice corrispondente che supporta la calibrazione si trova nel modulo MainPage.xaml.cs entro il compass_Current­gestore di evento ValueChanged, come mostrato Figura 3.

Figura 3 taratura della bussola

...
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");
 }
}

Una volta ottenuta la precisione desiderata, all'utente viene richiesto di premere il pulsante Done, che nasconde la schermata di calibrazione e visualizza schermata principale dell'applicazione.

La schermata principale questa schermata Visualizza una voce numerico o alfa e valore reciproco. Inoltre, rende il viso di una bussola che ha orientato rispetto al Nord vero. Infine, i display schermo primario i quattro controlli (o pulsanti) che permette all'utente di modificare l'output come così come bloccare il valore della voce e volto della bussola.

Figura 4 Mostra schermo primario della mia applicazione, MainPage. xaml, come appare in Visual Studio.

The App’s Primary Screen in Visual Studio
Figura 4 l'App di primario dello schermo in Visual Studio

La maggior parte degli elementi dell'interfaccia utente nella schermata principale sono semplici controlli TextBlock e pulsante. I blocchi di testo di identificare la voce e il suo valore reciproco. I pulsanti consentono all'utente di controllare l'output. Tuttavia, il volto di bussola è un po' più complessa.

Il volto di bussola la faccia della bussola è costituito da tre componenti: un'immagine di sfondo, un'immagine in primo piano e una più grande, al confine con ellisse in cui ruotano le immagini di sfondo e primo piano. L'immagine di sfondo contiene le lettere corrispondenti ai quattro punti su una bussola, una linea orizzontale e una linea verticale. L'immagine in primo piano crea l'effetto vetro affumicato.

L'immagine di sfondo In XAML, l'immagine di sfondo è denominata CompassFace (questo nome variabile si fa riferimento nel codice che ruota la bussola faccia):

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

L'immagine in primo piano primo piano del viso bussola, EllipseGlass, è definito nel codice XAML stesso. Il effetto vetro affumicato viene creato utilizzando un pennello sfumatura lineare. Creato questa ellisse utilizzando Microsoft Expression Blend 4. Lo strumento di Expression Blend è compatibile con Visual Studio e consente di caricare XAML dell'applicazione e migliorare l'interfaccia utente di personalizzare la grafica. Figura 5 Mostra l'Expression Blend editor come appariva durante la creazione dell'ellisse ombreggiato.

Creating a Shaded Ellipse in Expression Blend
Figura 5 creando un ellisse ombreggiata in Expression Blend

Dopo aver finito l'ellisse in Expression Blend di editing, il codice XAML nel mio progetto di Visual Studio è stato aggiornato con il codice XML seguente:

<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>

Si noti che le dimensioni di EllipseGlass (263 x 263 pixel) sono una corrispondenza esatta delle dimensioni di compass.png. Si noti inoltre che il nome dell'oggetto, EllipseGlass, viene fatto riferimento nel codice che esegue la rotazione del viso bussola.

Il bordo del viso bussola il volto bussola ruota all'interno di un'ellisse più grande, bianco con un bordo rosso. Questa ellisse è definita nel codice XAML e denominata EllipseBorder:

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

Il codice dietro l'interfaccia

Il codice si trova nel file MainPage.xaml.cs nel download del codice, e accede a spazi dei nomi necessari per l'applicazione, inizializza il sensore, imposta un intervallo di report e gestisce le varie caratteristiche di applicazione: calibrazione, ruotando il viso bussola, alterna tra numerico e alfa e così via di uscita.

La bussola nel tuo codice di accesso il primo passo nella scrittura di un'applicazione bussola (o qualsiasi applicazione che accede a uno dei sensori telefono) è di ottenere l'accesso agli oggetti sensore esposti nello spazio dei nomi Microsoft.Devices.Sensors. Questa operazione viene eseguita con la seguente direttiva using in MainPage.xaml.cs:

using Microsoft.Devices.Sensors;

Una volta questo utilizzando direttiva appare nel file, riesco a creare una variabile bussola che mi dà l'accesso a livello di codice per il dispositivo effettivo del telefono:

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

Userò questa variabile per avviare la bussola, fermarlo, recuperare la precisione voce corrente, impostare l'intervallo di report e così via.

A partire della bussola e impostare la frequenza di relazione una volta a creare la variabile di bussola, posso iniziare a richiamare metodi e impostazione delle proprietà dell'oggetto. Il primo metodo che viene richiamato è il metodo Start, che mi permette di iniziare a ricevere i dati dal sensore. Dopo l'avvio della bussola, impostare l'intervallo di report — il tempo tra gli aggiornamenti di sensore — a 400 ms (si noti che la proprietà TimeBetweenUpdates richiede un multiplo di 20 ms):

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

Il valore di 400 ms è stato scelto per prova ed errore. L'intervallo predefinito di relazione è estremamente breve. Se si tenta di eseguire l'applicazione a questo valore predefinito, il volto di bussola è ruotato così frequentemente che sembra essere instabile.

Creazione di gestori eventi bussola la bussola app supporta due gestori eventi: uno che visualizza la pagina di calibrazione (taratura­StackPanel) e un altro che rende la voce corrente e ruota la bussola faccia.

Definire e stabilire il gestore di eventi di calibrazione il gestore di eventi di calibrazione contiene relativamente poche righe di codice. Questo codice, mostrato Figura 6, compie due compiti principali: in primo luogo, Visualizza la schermata di calibrazione che è definita nel file MainPage. Xaml; in secondo luogo, imposta una calibrazione variabile Boolean true.

Figura 6 il gestore di eventi di calibrazione

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);
  }
}

Perché questo gestore eventi viene chiamato da un thread in background, non ha accesso diretto al thread dell'interfaccia utente. Così, per visualizzare la schermata di calibrazione, è necessario chiamare il metodo BeginInvoke sull'oggetto Dispatcher.

La calibratura variabile booleana viene esaminata all'interno del codice per il gestore di eventi valore modificato (compass_CurrentValueChanged). Quando questa variabile è true, ignoro la bussola e aggiornare la schermata di calibrazione con i più recenti dati di taratura. Quando la variabile è falsa, aggiornare le letture della bussola ed eseguire rotazioni del viso bussola.

Questo gestore eventi viene stabilito nel costruttore MainPage con la seguente riga di codice:

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

Definire e stabilire il gestore Value-Changed viene richiamato il gestore di evento di modifica valore (compass_CurrentValueChanged) ogni volta che una nuova lettura arriva dalla bussola. E, a seconda dello stato della taratura variabile, o aggiorna la schermata di calibrazione o aggiorna la schermata principale.

Quando è l'aggiornamento dello schermo primario, il gestore eventi esegue le attività seguenti:

  • Calcola le rubriche vera e reciproche rispetto al Nord vero.
  • Ruota la bussola faccia.
  • Rende le voci correnti e reciproche.

Le rubriche di calcolo l'esempio di codice riportato di seguito viene illustrato come il gestore eventi recupera la voce rispetto al vero Nord utilizzando la proprietà TrueHeading dell'oggetto SensorReading:

 

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

Figura 7 viene illustrato come il gestore eventi aggiorna le voci correnti e reciproche.

Figura 7 l'aggiornamento corrente e reciproco rubriche

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";
  }
}

Ruotando la faccia della bussola il frammento di codice seguente viene illustrato come l'app consente di ruotare le due ellissi che costituiscono lo sfondo e primo piano del viso bussola:

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;

La variabile CompassFace corrisponde all'immagine di sfondo che contiene i quattro punti della bussola (N, E, W e S) e la linea orizzontale e verticale. La variabile EllipseGlass corrisponde allo strato di vetro affumicato.

Prima posso applicare una trasformazione di rotazione, è necessario garantire che la trasformazione è centrata su due oggetti che potrai ruotare. Questo viene fatto richiamando il metodo RenderTransformOrigin su ogni oggetto e fornendo le coordinate (0.5, 0.5). (Per ulteriori informazioni su questo metodo e il suo utilizzo, fare riferimento alla pagina MSDN Library, "Proprietà RenderTransformOrigin," a bit.ly/KIn8Zh.)

Una volta che ho centrato la trasformazione, posso calcolare l'angolo ed eseguire la rotazione. Sottraendo la direzione attuale da 360 a calcolare l'angolo. (Questo è il titolo che ho appena ricevuto nel gestore dell'evento). Applico questo nuovo angolo con la proprietà RenderTransform.

Blocco e sblocco la bussola il blocco e sblocco­ing caratteristica era destinato a qualcuno all'esterno che sta usando l'app per navigare (se in una barca o a piedi su un sentiero con mappa in mano). Questa funzionalità è semplice; richiama il metodo Stop sulla bussola per bloccare la voce e poi richiama il metodo Start per riprendere il recupero della rubrica.

Il metodo Stop viene richiamato quando l'utente preme LockButton:

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

Il metodo Start viene richiamato quando l'utente preme UnlockButton:

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);
  }
}

Si noti che oltre a riavviare la bussola, reimpostare l'intervallo di report a 400 ms per garantire un comportamento coerente.

Commutazione tra numerico e rubriche alfa il codice che commuta tra alfa e rubriche numerici è controllato da una singola variabile Boolean denominata alfabetica che viene impostato quando un utente preme AlphaButton o NumericButton. Quando l'utente preme AlphaButton, questa variabile è impostata su True; Quando l'utente preme NumericButton, esso è impostata su False.

Di seguito è riportato il codice per l'evento click di AlphaButton:

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

Il codice nel gestore eventi compass_CurrentValueChanged esamina alfabetica per determinare se devono eseguire il rendering delle rubriche numeriche o alfa.

Sostenere la luce e il buio visibilità temi dopo aver creato l'app e presentato ai App Hub per la certificazione, sono rimasto sorpreso di ricevere una notifica che esso aveva fallito perché alcuni elementi dell'interfaccia utente è sparito quando è stato testato il tema luce visibilità. (Era stato in esecuzione esclusivamente con il tema scuro e non era riuscito a testare il tema luce).

Per risolvere questo problema, ho aggiunto il codice per il costruttore MainPage, che recupera il tema corrente e quindi imposta il colore di primo piano degli elementi dell'interfaccia utente (blocchi di testo e pulsanti) per lavorare con il tema dato. Se è impostato il tema della luce, i colori di primo piano degli elementi sono impostati su nero e rosso. Se è impostato il tema scuro, i colori di primo piano degli elementi vengono impostati al grigio scuro e chiaro. Figura 8 illustrato questo codice.

Figura 8 coordinamento temi e colori

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;
}

Divertimento e preziosi

La creazione di questa app era un sacco di divertimento, ed era così prezioso. Dopo aver lavorato con un sensore nella piattaforma Windows Phone, ormai di una più chiara comprensione delle differenze tra questa piattaforma e il supporto del sensore in Windows 8. Ma che cosa mi ha colpito la maggior parte erano le somiglianze. La mia impressione è che se sei uno sviluppatore Windows Phone che ha trascorso qualche tempo con il sensore dello spazio dei nomi, tu stai andando a trovare la migrazione a Windows 8 eccezionalmente semplice. E, in Windows 8, troverete sensori addizionali quali l'inclinometro, sensore di orientamento e sensore di orientamento semplice. (Il sensore di orientamento è una fusione di più sensori che restituisce un quaternione, o matrice di rotazione, è possibile utilizzare per controllare i giochi complessi. Il sensore di orientamento semplice consente di rilevare se il dispositivo è in modalità ritratto o paesaggio, come pure rivolto verso l'alto o rivolto verso il basso.)

Le opportunità di sviluppo offerte da tutti questi sensori sono entusiasmanti, e vedo l'ora di vedere i modi fantasiosi che nostro creative developer community può mettere loro di utilizzare.

Donn Morse è uno scrittore di programmazione senior del team Windows in Microsoft, che per il passato parecchi anni si è concentrata sulla piattaforma sensore, dal lato di applicazione per il driver. Lui è appassionato e affascinato dai sensori e loro uso.

Grazie all'esperto tecnica seguente per la revisione di questo articolo: Jason Scott