Technology Experience

.NET World

Programmazione, libri, snippet di codice, articoli tecnici

.NET World

WP7, SoundEffect, frequenza di campionamento e Audacity

Dunque, faccio un breve riassunto. Per fare il play di suoni all’interno di una applicazione Windows Phone 7, abbiamo essenzialmente due metodi diversi:

  1. usando un MediaElement
  2. usando la classe SoundEffect

Il primo è disponibile solo all’interno di applicazioni Silverlight, il secondo è disponibile sia in Silverlight che in XNA.

In questo post parliamo della classe SoundEffect, e dei files .wav che è in grado di prendere in pasto e da mandare in play. Essenzialmente si tratta di avere del codice che fa una cosa simile:

SoundEffect slideEffect;
private void prepareSoundEffects()
{
    slideEffect = SoundEffect.FromStream(TitleContainer.OpenStream("Slide.wav"));
}

 

In questo caso carico il file Slide.wav. Quando ci sarà bisogno di farlo sentire all’utente è sufficiente chiamare il metodo Play(). Nulla di particolarmente complicato. Ricordiamoci che nel code-behind di App.xaml bisogna fare quanto segue:

readonly DispatcherTimer timer = new DispatcherTimer();

public App()
{
    this.timer.Tick += (s, e) =>
    {
        FrameworkDispatcher.Update();
    };

    this.timer.Interval = TimeSpan.FromMilliseconds(100);
    this.timer.Start();

    UnhandledException += Application_UnhandledException;
    InitializeComponent();
    InitializePhoneApplication();
}

 

Non so bene il perchè di questa cosa, so solo che bisogna farla! Sorriso

Che tipo di files posso far sentire?

Soltanto files .wav: gli mp3 in questo frangente non sono ammessi. Se tentate di caricare un file .mp3 otterrete una InvalidOperationException. Potete caricare solamente files .wav campionati a 44100Hz.

Ora, se siete come me, probabilmente in questi giorni state scandagliando il Web alla ricerca di questo o quell’effetto sonoro che sì, sul click di quel Button ci sta proprio bene. Però non tutti i files sono a 44100Hz: cosa succede, in questo caso? Che otterrete ancora una bella InvalidOperationException, proprio al momento del caricamento che abbiamo visto prima.

E quindi? Quindi vi consiglio di scaricare Audacity, che è un free digital audio editor disponibile su SoundForge. Audacity è disponibile ovviamente in download, sia in formato zip, che nel classico installer .msi. Avviate Audacity, aprite il file .wav che volete modificare e reimpostate la frequenza di campionamento, impostandola su 44100Hz.

Ma anche qui c’è una piccola precisazione da fare. Date un’occhiata a questo screenshot:

Audacity

Audacity riporta la frequenza di campionato in due punti diversi. Nell’esempio qui sopra ho aperto un file audio a 11025Hz. Se volete portare la frequenza a 44100Hz, per renderlo compatibile con la SoundEffect di XNA, cambiate quella che ho evidenziato dal rettangolo verde – in basso a sinistra nella finestra. Se toccate quella evidenziata dal rettangolo rosso, il suono risulterà distorto – perchè ovviamente modificare il campionamento significa anche “accelerare” il suono (un po’ come mandare un vecchio vinile 33 giri a 45).

Per salvare il file con le nuove impostazioni, usate il menu File –> Export As WAV… ed il gioco è fatto.

Send to Kindle
.NET World

Come ripristinare il PivotItem corretto dopo il tombstoning

Faccio il mea-culpa e correggo il tiro, in riferimento al mio post di ieri pomeriggio.

Il modo corretto di ripristinare il PivotItem dopo un tombstoning è quello di farlo nell’evento Loaded della Page.

Quindi:

protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
    appStatus.State["PageIndex"] = this.Pivot.SelectedIndex;
    base.OnNavigatedFrom(e);
}

 

Qui salviamo nello stato dell’applicazione il SelectedIndex del Pivot. Quando si ritorna all’applicazione succede quanto segue:

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
    if (appStatus.State.ContainsKey("PageIndex"))
        pageIndex = (int)appStatus.State["PageIndex"];

    base.OnNavigatedTo(e);
}

 

Qui carichiamo la situazione salvata precedentemente. Notare che pageIndex è definita a livello di classe, ed in questa fase semplicemente ne carichiamo il valore. Dentro l’evento Loaded della Page andiamo a settare il PivotItem:

private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
    if (pageIndex >= 0)
        this.Pivot.SelectedIndex = pageIndex;
}

 

Nell’evento Loaded siamo sicuri che la pagina sia stata interamente caricata, perciò non avremo problemi di alcun tipo.

Resta da capire perchè il codice descritto ieri si schianti solo con certi valori di SelectedIndex, e soprattutto perchè a run-time (in esecuzione senza breakpoint, tanto per capirci) vedo il controllo Pivot prendere il focus e poi…Boom! Mah!

Grazie al buon Gabriele che, nonostante non si stia occupando di sviluppo WP7, non ha perso il post dell’amico Matteo che spiegava questa cosa.

Send to Kindle
.NET World

Pivot, PivotItem e tomb-stoning: strano problema, qualcuno mi sa dire il perchè?

Sì, ehm, voglio dire, qualche problema c’è. Aprite Visual Studio 2010 e cominciate un nuovo progetto di tipo Windows Phone Application. Nei riferimenti aggiungete l’assembly Microsoft.Phone.Controls, in modo da poter utilizzare il controllo Pivot. Nella pagina MainPage.xaml, quella creata di default, cancellate tutto e fate in modo che il content sia il seguente:

<controls:Pivot x:Name="Pivot" >
    <controls:PivotItem Header="Item 1" />
    <controls:PivotItem Header="Item 2" />
    <controls:PivotItem Header="Item 3" />
    <controls:PivotItem Header="Item 4" />
    <controls:PivotItem Header="Item 5" />
</controls:Pivot>

 

E’ un semplice Pivot con 5 pagine PivotItem, identificabili dall’header che va da “Item 1” a “Item 5”. Ora supponiamo di voler gestire il tombstoning, ovvero se l’utente interrompe l’utilizzo dell’applicazione mentre si trova su ”Item 3”, quando la riprende deve ritornare su quella pagina. Idem ovviamente per le altre. Quindi:

PhoneApplicationService appStatus = PhoneApplicationService.Current;

protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
    appStatus.State["PageIndex"] = this.Pivot.SelectedIndex;
    base.OnNavigatedFrom(e);
}

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
    if (appStatus.State.ContainsKey("PageIndex"))
        this.Pivot.SelectedIndex = (int)appStatus.State["PageIndex"];

    base.OnNavigatedTo(e);
}

 

Il tutto è ovviamente definito nel code-behind MainPage.xaml.cs.

Qualcuno mi sa dire perchè se mi trovo su: Item 1, Item 2 o Item 5 la procedura di tombstoning funziona correttamente,

mentre se mi trovo su Item 3 o Item 4 l’applicazione crasha inesorabilmente?

Per comodità, vi metto a disposizione il file zip con la soluzione VS2010 pronta da aprire e provare. Ma solo a me succede?

Sad smile

Send to Kindle
.NET World

WP7 Developer Registration

Questa mattina ho registrato il mio nuovo WP7 – acquistato esattamente tre giorni fa – usando il tool Windows Phone Developer Registration (d’ora in poi WPDR) – che trovate comodamente nel menù Start sotto il gruppo di programmi Windows Phone Developer Tools. Questo tool richiede fondamentalmente tre cose:

  1. un cellulare Windows Phone 7 collegato al PC tramite cavetto USB
  2. il client Zune avviato (non ho provato con il WPConnect disponibile con i WP7 Developer Tools October Update)
  3. un account Live ID regolarmente attivato sul portale http://create.msdn.com

Quindi, è sufficiente inserire il vostro account e cliccare sul pulsante Register. Il vostro cellulare deve anche avere il display sbloccato e trovarsi quindi nella schermata iniziale, in qualche hub e via dicendo. Nota bene: rispetto al prototipo che ho avuto in dotazione per circa 2 settimane, ho notato che su questo LG è stata rimossa la possibilità di impostare “Mai” nell’opzione “Blocca lo schermo dopo”, disponibile in Impostazioni –> blocco e sfondo.

Questa mattina, sbloccando il mio per deployare da VS2010, mi sono accorto di una cosa. Se l’orologio del cellulare non è impostato in modo corretto, la registrazione del cellulare fallirà. Il messaggio di errore purtroppo non riesco a farvelo vedere, ho cercato di riprodurlo ma non c’è stato verso. Era una sorta di:

Please verify date and time on your phone, or verify Internet connection. Can’t connect to developer portal because date and time are different bla bla bla.

E’ bastato andare in Impostazioni –> data e ora –> ed attivare imposta automaticamente sulla voce SI. Fatto questo, sono riuscito ad abilitare il telefono per lo sviluppo.  Evidentemente è sufficiente avere l’orario sballato di 1-2 minuti per impedire la connessione e la registrazione del cellulare.

Send to Kindle
.NET World

Silverlight, controllo DatePicker e formattazione customizzata (con problemi di focus)

Mi sono scontrato con questo problema qualche giorno fa, ma trovo il tempo e la voglia di parlarne solo questa sera. Dunque, il tutto gira attorno a Silverlight ed al controllo DatePicker, dichiarato nel namespace System.Windows.Controls. La cosa interessante di questo controllo è che in tempi rapidi possiamo ottenere una view Silverlight come questa:

DatePicker01

che corrisponde più o meno alla seguente porzione di XAML:

<TextBox Grid.Row="0" Grid.Column="1" Height="26" />
<TextBox Grid.Row="1" Grid.Column="1" Height="26" />
<ctl:DatePicker Grid.Row="2" Grid.Column="1" Height="26" />
<TextBox Grid.Row="3" Grid.Column="1" Height="26" />

 

Tanto per chiarirci: la vista è una Grid, divisa in 2 colonne e 4 righe. Lo XAML qui sopra rappresenta il contenuto della colonna di destra, in pratica i 4 controlli di input: 3 TextBox per l’inserimento di cognome, nome e note, ed un DatePicker per l’inserimento della data di nascita. Nell’immagine qui sopra il DatePicker è evidenziato nel rettangolo verde.

Il controllo DatePicker è splendido e funziona bene, ma ha un piccolo difetto: non è possibile personalizzare il formato della data. Il controllo infatti dispone di una proprietà SelectedDateFormat, che però può valere solo Short o Long. Non potete specificare una string format customizzata, e quindi o vi vanno bene le due previste, oppure siete fregati. C’è una soluzione? Diciamo che googlando si trova un barbatrucco.

Questo barbatrucco consiste nell’usare due controlli separati invece di uno solo: più precisamente, una TextBox ed ancora il nostro DatePicker:

<TextBox Grid.Row="0" Grid.Column="1" Height="26" />
<TextBox Grid.Row="1" Grid.Column="1" Height="26" />
<toolkit:DockPanel Grid.Row="2" Grid.Column="1" LastChildFill="True">
    <ctl:DatePicker toolkit:DockPanel.Dock="Right" Width="23" />
    <TextBox toolkit:DockPanel.Dock="Left" Height="26" />
</toolkit:DockPanel>
<TextBox Grid.Row="3" Grid.Column="1" Height="26" />

 

Notate come è cambiata la terza riga. Ho usato un DockPanel (panel che adoro, onestamente) e dentro ho inserito i due controlli. Giocando con la proprietà LastChildFill=”True” faccio in modo che la TextBox riempia tutto lo spazio disponibile, mentre del DatePicker faccio comparire solamente il minimo indispensabile, ovvero il calendarietto che l’utente deve cliccare per scegliere la data. Ovviamente in un ambiente reale, realizzato con MVVM, la TextBox ed il DatePicker sarebbero bindate alla stessa proprietà, con il vantaggio però che nel binding di una normale TextBox posso specificare la stringa di formattazione che voglio. La UI appare come segue:

DatePicker02

Molto simile, praticamente nella UI non si vede alcuna differenza. Invece dal punto di vista della usability, una piccola differenza c’è. Se l’utente è abituato a navigare da un controllo all’altro premendo TAB, vedrà che c’è un piccolo problemuccio. La sequenza del TAB infatti è la seguente:

  1. TextBox del Cognome (come in figura)
  2. TextBox del Nome
  3. vuoto, boh, non si vede
  4. TextBox della Data di Nascita
  5. TextBox delle Note varie

Quel vuoto, boh, non si vede è ovviamente il DatePicker, che al momento opportuno si prende il focus. Piccola osservazione: graficamente questo focus non si vede, e soprattutto non c’è alcuna combinazione di tasti che fa apparire il calendario per scegliere la data, quindi sono obbligato ad usare il mouse. La conclusione di tutto ciò è la seguente: per passare dal Nome alla Data di Nascita l’utente deve premere due volte TAB, il che non va molto bene. Un utente evoluto magari capisce al volo, ma un altro magari no, e nonostante questo, diciamolo pure: è proprio brutto.

Come si risolve questa cosa? Beh, il DatePicker è un Control, quindi…direte voi…basta impostare IsTabStop=”False” sul controllo ed il gioco è fatto.

Falso.

Anche mettendo IsTabStop=”False” il DatePicker si prende il focus esattamente come prima. E quindi? Quindi vuol dire che qualcosa dentro il controllo ruba comunque il focus, anche se noi gli abbiamo detto di no. E quindi bisogna usare le armi pesanti, ovvero lavorare sul template interno del controllo.

Come fare? Seguite i semplici passi (cercherò di essere breve):

  1. Aprite Expression Blend 4.0
  2. Cominciate un nuovo progetto di tipo Silverlight 4.0
  3. Aggiungete alla MainPage un controllo DatePicker, avendo prima aggiunto nei riferimenti l’assembly

    C:Program Files (x86)Microsoft SDKsSilverlightv4.0LibrariesClientSystem.Windows.Controls.dll
  4. A questo punto cliccate con il destro sul controllo, andate su Edit Template e poi su Edit a Copy
  5. Assegnate pure un nome alla nuova risorsa Style che Blend sta per creare
  6. Passate alla vista XAML, copiate lo style DatePickerStyle1 ed incollate dentro Visual Studio 2010

Lo stile è come al solito piuttosto complesso, perchè contiene TUTTO ciò che serve al runtime di Silverlight per disegnare il controllo. Quindi avete colori, altri controlli, animazioni, effetti, etc. etc. Vi aiuterò e vi semplificherò la vista: con un pezzettino di altro codice (che vi risparmio) sono riuscito a capire qual’è il controllo che ruba il focus. Ed è esattemente il seguente:

<System_Windows_Controls_Primitives:DatePickerTextBox
    x:Name="TextBox"
    BorderBrush="{TemplateBinding BorderBrush}"
    BorderThickness="{TemplateBinding BorderThickness}"
    Background="{TemplateBinding Background}"
    Grid.Column="0"
    Padding="{TemplateBinding Padding}"
    SelectionBackground="{TemplateBinding SelectionBackground}"/>

 

Questo è il controllo maledetto che ruba il focus. E’ sufficiente mettere qui IsTabStop=”True” per risolvere tutti i vostri problemi. Fatto questo, il TAB funziona regolarmente, saltate da un controllo all’altro senza che nessuno vi rubi il focus, potete formattare le date come volete voi, etc. etc.

Alla prossima.

Send to Kindle
.NET World

Presentazione "”Flight Simulator X Viewer” per WP7

Ho girato ieri sera il video, dopo cena. E’ un po’ più lungo e complicato rispetto alle mie altre applicazioni per Windows Phone 7. il filmato dura circa 15 minuti, perciò mettetevi comodi.

Video di presentazione

 

Come ho spiegato nel filmato, tutto l’ambaradan è composto da due software: uno deve girare sul PC desktop su cui state effettuando il volo, e difatti l’ho chiamato Flight Simulator X Tracer. Questo componente si occupa di aggiornare tutti i parametri di volo che state facendo su un server VivendoByte.net. E’ una normalissima applicazione WPF 4.0 che fa uso di un servizio WCF per tutte le operazioni. Tramite una slider è possibile regolare con precisione la frequenza di aggiornamento.

L’applicazione per Windows Phone 7 invece è il vero e proprio viewer. Utilizzando lo stesso servizio WCF citato prima, scarico l’elenco dei voli attivi per mostrarli all’utente, e toccandone uno si accede alla Bing Map che graficamente ci fa vedere dove si trova il nostro aereo: in quale posizione, a che altitudine, rotta, etc. etc. L’elenco delle variabili che FSX può gestire è davvero elevatissimo: date un’occhiata a questa pagina di MSDN: se c’è qualcuno fra voi che credeva che FSX è un videogioco, farebbe meglio a cambiare idea.

Una piccola precisazione: questa accoppiata di applicazioni è stata studiata per monitorare i voli attivi. Per questo motivo non c’è alcuno storico. Ed è per lo stesso motivo per cui quando alla fine del volo cliccate sul pulsante Stop Flight tutti i dati del volo vengono cancellati. Semplicemente non c’è più alcun “flight in progress” da monitorare. Quando all’avvio del tracer create il volo cliccando sul pulsante, questo volo compare automaticamente e pubblicamente a tutti quelli che in quel momento stanno usando il viewer: difatti, non esiste il concetto di volo privato. E va da sè quindi che volendo posso seguire il volo che sta facendo qualcun’altro.

Send to Kindle
.NET World

Problemi con l’emulatore Windows Phone 7

Dunque, preciso che non sono molto facilmente riproducibili, per cui anche per me è particolarmente difficile spiegarli.

Però prendete appunti, potrebbe essere utile. Smile

Il problema principale avviene quando tentate il solito deploy da VS2010 sull’emulatore. Da VS2010 vedere “Deploy started…”, ma questo praticamente non finisce mai. Rimane appeso.

Innanzitutto, lasciate che sia VS2010 ad avviare l’emulatore: è sufficiente premere F5 ed il gioco è fatto. Se avviate separatemente l’emulatore dal menù Start e poi eseguite la solution da VS2010, il deploy fallirà, e nella Error List troverete una cosa tipo “The communication resource (port) is already be used by another program.”.

In altre circostanze non meglio precisate nella Error List otterrete un bel “The data necesssary to complete this operation is not yet available.”. Questo errore lo ottenete nel momento in cui fate un bel Build –> Cancel build per uscire dal deploy infinito raccontato prima. Per eliminarlo, non c’è verso, se non quello di chiudere tutto (sia l’emulatore, che VS2010) e di riavviare.

Altro appunto: capita a volte che l’emulatore ci metta una vita ad avviarsi (una vita == “> 3 minuti”), quando solitamente ci mette una manciata di secondi. Questo si verifica solo sul mio notebook, e solo quando lo risveglio da un eventuale stato di stand-by. E’ sufficiente un riavvio per risolvere la cosa.

Ultima cosa: ricordatevi che potete fare Clean Solution. A volte serve per evitare alcuni problemi di questo tipo.

Googlando si trovano poche informazioni, ovviamente, dato che tutto l’ambiente è un pochino nuovo. E mi piacerebbe sapere come se la stanno cavando gli altri, voi developer che avete usato solo l’emulatore, perchè ho l’impressione che tutti questi problemi siano sorti dopo aver switchato da un WP7 reale a quello emulato.

Send to Kindle
.NET World

Windows Phone 7, Silverlight e la gestione dei suoni

Se preferite utilizzare Silverlight per creare le vostre applicazioni, perchè magari è più intuitivo, o semplicemente perchè Silverlight è la tecnologia che si presta meglio per fare quello che avete in testa, prima o poi dovrete scontrarvi con la gestione dei suoni. Mica è necessario, se però magari fate un piccolo videogioco, oppure volete condire l’interazione con l’utente con qualche effettino, la cosa può risultare gradevole. Io personalmente non ho riscontrato grandi difficoltà quando ho creato Keyzard, però qualche gabola c’è.

Spero in questo post di poter fornire a chi verrà dopo di me qualche consiglio utile.

Inserite <MediaElement/> nelle vostre pagine ed il gioco è fatto
E’ semplice: nella pagina XAML in cui volete fare qualche suono, inserite un elemento MediaElement. Mettetelo pure nascosto (Visibility = Collapsed) e dategli un bel nome (x:Name=”MediaPlayer”) – in questo modo visivamente non apparirà nulla, e potete comandarlo & gestirlo nel code-behind.

Attenzione: una delle grosse limitazioni è che potete inserire un solo MediaElement per pagina. Se ne inserite più di uno, non avete alcun errore di compilazione o a runtime, semplicemente quelli in più vengono ignorati.

Occhio che Zune blocca tutto!
Per sviluppare, deployare e debuggare le vostre applicazioni, utilizzate ovviamente la coppia Visual Studio 2010 + Zune. Attenzione, però: quando Zune è aperto, qualsiasi play generato attraverso MediaElement viene bloccato. Quindi, supponiamo:

<Grid Background="Transparent">        
    <MediaElement Source="Avvio.mp3" x:Name="MediaPlayer1" />
</Grid>

 

Compilate, avviate e non sentirete un bel nulla. Tenete pure collegato il WP7, chiudete Zune e lanciate dal cellulare l’applicazione. Questa volta sentirete il suono che avete impostato.

I files audio permessi quali sono? Files .mp3 o wav, ed impostateli come Resource

Più semplice di così si muore. Potete inserire nella vostra solution files .mp3 o files .wav. Assicuratevi di aver impostato come Build Action “Resource”, che dovrebbe comunque essere il valore di default.

Gestione del suono da code-behind

Allora, tenete presente che la proprietà AutoPlay dell’oggetto MediaElement è True. Quindi la porzione di XAML nel paragrafo precedente fa partire immediatamente il suono, appena la pagina viene renderizzata sul display del WP7. Ovviamente è possibile impostare AutoPlay=”false” in questo modo:

<Grid Background="Transparent">
    <MediaElement AutoPlay="False" Source="Avvio.mp3" x:Name="MediaPlayer1" />
</Grid>

 

A questo punto da code-behind è sufficiente chiamare il metodo Play() dell’oggetto MediaPlayer1 per sentire il suono. Attenzione: non mettere questa chiamata nel costruttore, oppure di seguito all’InitializeComponent(), perchè il MediaElement non sembra reagire. Piuttosto usate l’evento Loaded della phone:PhoneApplicationPage e quindi:

private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
    this.MediaPlayer1.Play();
}

 

Danza dello stesso MediaElement con più suoni diversi

La cosa più fastidiosa con cui ho avuto a che fare è questa: dal momento che possiamo inserire un solo MediaElement sulla pagina, va da sé che dobbiamo continuare reimpostare la proprietà Source in base a quello che ci serve in quel momento. Quindi:

  • All’inizio Source è “Avvio.mp3”
  • L’utente clicca un bottone e vorremmo sentire “Sparo.wav”
  • L’utente tocca qualcosa e vorremmo sentire “Urlo.mp3”
  • Finisce il tempo, vorremmo sentire “GameLose.mp3”

La prima cosa che vorreste fare è probabilmente la seguente:

this.MediaPlayer1.Source = new Uri("Loser.wav", UriKind.RelativeOrAbsolute);
this.MediaPlayer1.Play();

 

Qui possono nascere dei problemi. E’ un po’ tutto casuale, però a volte il Play(); non fa sentire nulla. Perchè? Credo perchè la reimpostazione del Source avviene in modo asincrono, quindi a volte viene eseguito il Play() prima che il nuovo file sia stato effettivamente caricato (dipende dalla dimensione, I suppose). Come risolvere? Io ho risolto in questa maniera:

public MainPage()
{
    InitializeComponent();
    this.MediaPlayer1.MediaOpened += (o, s) =>
        {
            this.MediaPlayer1.Position = TimeSpan.Zero;
            this.MediaPlayer1.Play();
        };
}

 

In pratica, nel costruttore della pagina dico: ogni volta che c’è un evento MediaOpened, fai il Play() del file stesso. Notare che reimposto anche Position, in modo tale da posizionarmi all’inizio dello stream audio. Quindi, nel momento in cui voglio sentire un certo suono è sufficiente reimpostare il Source ed il gioco è fatto. Una riga simile…

this.MediaPlayer1.Source = new Uri("Loser.wav", UriKind.RelativeOrAbsolute);

 

…farebbe partire in modo automatico il suono senza sforzi.

Aspettare la fine di un suono prima di fare qualcos’altro

Ecco lo scenario: in Keyzard, quando il vostro cowboy viene colpito da un proiettile non dice niente. Semplicemente si passa al round successivo. Quando perde tutte le vite, invece, fa un urlo un po’ prolungato – poverino, sta morendo Smile, e dopo si naviga alla pagina di Game Over. Se adottate solo la tecnica del paragrafo precedente…supponiamo…

if (numberLives == 0)
{
    this.MediaPlayer1.Source = new Uri("UrloDiChiMuore.wav", UriKind.RelativeOrAbsolute);
    this.NavigationService.Navigate(new Uri("GameOverPage.xaml", UriKind.RelativeOrAbsolute);
}

 

…non va troppo bene: il suono comincia, dura una frazione di secondo, poi si naviga sulla pagina indicata. Dovete aspettare la fine dell’urlo, e solo dopo spostarvi di pagina.

Come si risolvre questa cosa? E’ sufficiente gestire l’evento MediaEnded in questo modo:

private void gameOver()
{
    if (numberLives == 0)
    {
        this.MediaPlayer1.MediaEnded += (o, s) =>
            {
                this.NavigationService.Navigate(new Uri("GameOverPage.xaml", UriKind.RelativeOrAbsolute);
            };

        this.MediaPlayer1.Source = new Uri("UrloDiChiMuore.wav", UriKind.RelativeOrAbsolute);
    }
}

 

In pratica, si fa la .Navigate solo al termine del nostro suono. Piuttosto elementare.

Attenzione al MediaEnded e al suono disattivato

In un’applicazione seria dovreste avere un bool da qualche parte (nei Settings?) per ricordarvi se l’utente vuole o non vuole il suono attivo. Se questo bool è false evito di reimpostare il Source e quindi non sento nulla. Attenzione! Se vi è servito gestire il MediaEnded descritto prima per navigare in modo sincrono, questo evento non si scatena, ovviamente perchè fisicamente non è stato caricato e playato alcun file, e quindi il .Navigate() non viene mai eseguito. Quindi attenzione! Ecco un codice brutto, forse, ma che funziona:

private void gameOver()
{
    if (numberLives == 0)
    {
        this.MediaPlayer1.MediaEnded += (o, s) =>
            {
                this.NavigationService.Navigate(new Uri("GameOverPage.xaml", UriKind.RelativeOrAbsolute);
            };

        if(utente_vuole_i_suoni)
            this.MediaPlayer1.Source = new Uri("UrloDiChiMuore.wav", UriKind.RelativeOrAbsolute);
        else
            this.NavigationService.Navigate(new Uri("GameOverPage.xaml", UriKind.RelativeOrAbsolute);
    }
}

 

Conclusioni

La cosa è semplice: se volete un suono di avvio, oppure non c’è molta interazione, allora ve la cavate con poco. Invece potreste trovarvi nelle condizioni di sincronizzare un po’ gli eventi, e quindi dovete organizzarvi meglio. Spero di aver aiutato qualcuno! Ho parzialmente scritto codice direttamente in WLW, per cui potrebbero esserci bachi: perdonatemi!

Smile

Send to Kindle
.NET World

Windows Phone 7 e le icone nell’application bar

Una buona abitudine da seguire quando si sviluppano applicazioni per WP7 è quello di sfruttare la zona denominata Application Bar, che si trova nella parte inferiore dello schermose tenete il telefono in posizione Portrait, oppure sul lato destro dello schermose tenete il telefono in posizione Landscape.

Nell’Application Bar potete inserire una o più icone, a seconda delle vostre necessità, che fanno un qualcosa quando l’utente le clicca. Ecco quindi il pulsante Refresh, il pulsante Settings, il pulsante Nuovo tweet, etc. etc.

Dove trovate le icone? Non girovagate troppo per il Web, per due motivi. Il primo è quello di tener presente che al primo posto c’è il nostro utente, e quindi se su WP7 ci sono n applicazioni, ognuna delle quali usa un’icona Refresh diversa, probabilmente lo stiamo confondendo e basta. Quindi evitiamo inutili complicazioni.

Per farla breve, andate nella directory C:Program Files (x86)Microsoft SDKsWindows Phonev7.0Iconslight del vostro PC e usate questi PNG. Ovviamente questa directory esiste se avete installato i developer tools per WP7. Usate questi, e non quelli contenuti in “dark”, perchè questi hanno lo svantaggio di smettere di funzionare se l’utente switcha il tema da dark a light e viceversa. Se usate il tema light, tutto ok, mentre quando usate il dark le icone non si vedono più.

Usate quelle in C:Program Files (x86)Microsoft SDKsWindows Phonev7.0Iconslight e siete a posto!

Grazie a Lorenzo per il tip!

Send to Kindle