Quasi XML e Regular Expressions Negative Lookup

Premessa:

Oggi mi sono trovato a dover risolvere una questione relativa alla “pulizia” di dati “quasi XML”, che all’interno dei tag XML possono eventualmente contenere il carattere “proibito” & (ampersand).

Com’è noto, tale carattere è un metacarattere che serve a rappresentare i caratteri non consentiti all’interno dei tags XML, secondo la nota tabella:

Tabella Metachars XML

La cosa è complicata per il fatto che i dati suddetti possono contenere sia ampersand errate (un ampersand solo soletto) e sia corretti (&amp;), com’è possibile vedere nell’esempio dove il valore contenuto nel <tag> è Mario scrive: "You & Me, forever!"

<tag>Mario scrive: &quot;You & Me, forever!&quot;</tag>

che dobbiamo trasformare in

<tag>Mario scrive: &quot;You &amp; Me, forever!&quot;</tag>

E’ evidente che non possiamo semplicemente sostituire ogni ampersand con &amp; perchè altrimenti otterremmo:

<tag>Mario scrive: &amp;quot;You &amp; Me, forever!&amp;quot;</tag>

Veniamo quindi all’oggetto di questo post:

Nelle espressioni regolari è possibile utilizzare il “Negative Lookup” per NON riconoscere un costrutto SE DOPO ce n’è un’altro.

Nel nostro caso in esempio, l’espressione regolare è

&(?!quot;)

che troverà tutti gli & non seguiti da quot;

e più in generale:

&(?!lt;|gt;|amp;|apos;|quot;)

That’s all folks!

WP7 e la geolocalizzazione

Nello sviluppo del client per Decoro Urbano, un aspetto essenziale è quello della localizzazione.

WP7 mette a disposizione un servizio che utilizza in modo efficiente tre fonti di dati, secondo la disponibilità: GPS, Wi-Fi e rete cellulare. vi sono due livelli di precisione (standard e alta) e la possibilità di definire un valore di distanza minima entro la quale non deve essere segnalata alcuna variazione di posizione. In tal modo il consumo della batteria viene ridotto al minimo. E’ comunque buona prassi, nello sviluppo della propria applicazione, attenersi alle buone pratiche d’uso descritte qui.

Io, per maggiore comodità, ho wrappato il servizio in una classe “GeoPosition” che gestisce il servizio (più o meno secondo qaunto descritto qui) esponendo le proprietà utili quali lo stato del servizio, la posizione, ecc. attraverso l’ INotifyPropertyChanged. In questo modo, inserendo nel ViewModel una proprietà di tipo GeoPosition posso aggiornare la view utilizzando il classico meccanismo di binding. Poiché al cambio di posizione corrisponde una chiamata al web service di Decoro Urbano che ritorna il nome del Comune ed alcune informazioni associate (ad esempio se tale Comune partecipa al progetto), è stato divertente provare sull’emulatore e scoprire che mi trovavo a Redmon, che al momento non partecipa a Decoro Urbano (ma mai dire mai!) :-D

PosizioneRedmond

Il motivo è semplice. Nell’emulatore il servizio fornisce la posizione di default. Cambiando manualmente la posizione nella mappa dall’apposita finestra dell’emulatore (ad esempio su viale Mazzini, a Roma), otteniamo in asincrono la modifica del testo nella view:

PosizioneRoma

Riassumendo: il Location Service aggiorna la proprietà posizione della classe“GeoPosition” che notifica il suo cambiamento mediante INotifyPropertyChanged, il mio ViewModel lancia una richiesta HTTP asincrona al servizio web di Decoro Urbano. Quando viene ricevuta la risposta viene modificata la proprietà “UserStatAndPositionDescription” che restituisce il testo da mostrare nella view. Anche quest’ultima modifica è segnalata tramite INotifyPropertyChanged e quindi la view viene automaticamente aggiornata.

Windows Phone Rulez!

Inutile, ma essenziale!

Alle volte le piccole cose inutili sono essenziali per per aggiungere un po’ di sale alla quotidianità.

Tra queste, a mio umilissimo parere, c’è la possibilità di modificare la skin dell’emulatore Windows Phone 7:

image

Questa e altre cose più serie nel post di Doug Rathbone: 8 Must-Have Tools for Windows Phone 7 Development

WP7 Emulator e Servizi Web

Un piacevole side-effect che ho riscontrato nell’uso di Fiddler con l’emulatore del Windows Phone è che “magicamente” hanno cominciato a funzionare anche le richieste ai servizi web che prima si rifiutavano di andare. Ho perso un bel po’ di tempo facendo varie prove, convinto che fossi io a sbagliare qualcosa, invece è prorpio l’emulatore che non ne voleva sentir parlare, visto che facendo gli stessi test con il telefono tutto filava liscio.

Devo ammettere che non ho capito bene da cosa dipenda, ma per il momento mi va bene così (ho altro più urgente di cui occuparmi).

Quindi, se vi dovesse capitare di aver difficoltà nell’esecuzione di comandi HTTP per accedere ai servizi web dall’emulatore WP7, scaricatevi Fiddler e impostatelo seguendo le indicazioni del precedente post.

Come si suol dire, due piccioni con una fava!

Usare fiddler con l’emulatore Windows Phone

Per usare fiddler con l’emulatore bisogna fare così:

1. Da “Tools | Fiddler Options” settare l’opzione evidenziata e confermare cliccando su OK:

image

2. Nella QuickExec box sotto la lista delle sessioni, digitare “prefs set fiddler.network.proxy.registrationhostname <Host> dove<Host> e il nome del vostro desktop:

image

3. Riavviare Fiddler.

4. Avviare (o riavviare) l’emulatore Windows Phone 7

Per verificare il funzionamento, aprire Internet Explorer nell’emulatore e controllare che il traffico venga visualizzato in Fiddler.

Maggiori info qui.

That’s all folks!

[WP7] Forzare il binding di una TextBox

Generalmente il binding two-way di una textbox aggiorna la proprietà a cui è bindata quando il controllo perde il focus.

Poiché però i pulsanti posizionati nel menu non spostano il focus della pagina, vediamo cosa accade in pratica:

Step1Step2

Il motivo è semplice: poiché la TextBox che contiene il cognome non ha perso il focus, il binding non ha aggiornato la proprietà sorgente (Binding source) del ViewModel, quindi il controllo della validità dei dati immessi ritorna l’errore. Peggio ancora, poiché di fatto il valore della proprietà bindata suddetta è ancora quello vecchio, nel nostro caso abbiamo un errore perché la nostra logica di business richiede un valore non vuoto e siamo partiti da zero, ma in caso di una maschera di editing dei dati, dove magari vogliamo correggere il valore contenuto nella textbox, di fatto senza accorgerci di nulla il programma utilizzerà il VECCHIO valore e non darà errore perché tale valore non è vuoto.

Se avessimo utilizzato un bottone nella pagina e non un ApplicationBarIconButton, il focus si sarebbe spostato sul bottone stesso e il binding avrebbe completato l’aggiornamento della sorgente senza problema alcuno.

Dunque risulta assolutamente necessario, nello scenario descritto, forzare il binding in modo da aggiornare la sorgente al contenuto delle TextBox e dell’eventuali PasswordBox.

Per farlo si può utilizzare il seguente codice, da inserire nel codice associato all'evento prodotto dal pulsante:

C#:
// Force two-way binding of the editing field
object focusObj = FocusManager.GetFocusedElement();
if (focusObj != null && (focusObj is TextBox || focusObj is PasswordBox))
{
    BindingExpression binding;
    if (focusObj is TextBox)
    {
        binding = (focusObj as TextBox).GetBindingExpression(TextBox.TextProperty);
    }
    else
    {
        binding = (focusObj as PasswordBox).GetBindingExpression(PasswordBox.PasswordProperty);
    }
    binding.UpdateSource();
}

That’s all folks!

Lab addicted…

image

Il Lab a Roma è stato un successo, e io bisso a Napoli!

WP7 Panorama e Bing Map

Sto sviluppando la versione per WP7 di Decoro Urbano, e ho deciso di realizzare un Panorama così fatto:

clip_image002

Ovviamente lo sfondo diventa chiaro se l’utente sceglie un tema a sfondo chiaro.

Il problema, segnalatomi da Lorenzo, sta nell’uso della mappa bing nel panorama. Funzionare funziona benissimo, è solo che si manifasta una incongruenza nella User eXperience, in quanto in un panorama l’utente deve poter scorrere le pagine, e questo non avviene se la gesture viene fatta nella mappa. Infatti in questo caso il componente Bing Map interpreta la gesture come una richiesta di scorrimento della mappa stessa. E’ chiaro che l’utente potrebbe comunque scorrere il contenuto del panorama eseguendo la gesture al di fuori della mappa (nel mio caso al di sopra) ma rimane una inconsistenza poco piacevole.

Io ho risolto incorporando la mappa come contenuto di un pulsante, del quale ho cambiato lo stile in modo tale da mostrare una leggera cornice solo quando tocco la mappa (di fatto quando tocco il pulsante che la contiene) in modo da dare un feedback visivo al “tocco”.

imageimage

La cosa funziona bene perché se la gesture è un “tocco”, il bottone esegue il codice associato all’evento Click, se invece si tratta di un “trascinamento”, il pulsante ignora la gesture e il panorama scorre.

L’evento click è associato ad una pagina di visualizzazione della mappa, che in questo caso è libera di interpretare le gesture come spostamento della mappa:

image

Di seguito il sorgente dello stile:

C#:
<Style x:Key="BingMapButtonStyle" TargetType="Button">
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="BorderBrush" Value="{StaticResource PhoneForegroundBrush}"/>
    <Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/>
    <Setter Property="BorderThickness" Value="{StaticResource PhoneBorderThickness}"/>
    <Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilySemiBold}"/>
    <Setter Property="FontSize" Value="{StaticResource PhoneFontSizeMediumLarge}"/>
    <Setter Property="Padding" Value="10,3,10,5"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Grid Background="Transparent">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal"/>
                            <VisualState x:Name="MouseOver"/>
                            <VisualState x:Name="Pressed">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneBackgroundBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneForegroundBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ButtonBackground">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneForegroundBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderThickness)" Storyboard.TargetName="ButtonBackground">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="5"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Disabled">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ButtonBackground">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="Transparent"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Border x:Name="ButtonBackground" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0" Background="{TemplateBinding Background}" CornerRadius="0" Margin="0">
                        <ContentControl x:Name="ContentContainer" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch"/>
                    </Border>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

e del bottone con la mappa:

C#:
<Button Style="{StaticResource BingMapButtonStyle}" Click="Button_Click">
    <bing:Map CredentialsProvider="<inserire qui le credenziali per connettersi a bing map>"
                IsEnabled="False" ZoomLevel="13">
        <bing:Map.Center>
            <my:GeoCoordinate Latitude="41.9" Longitude="12.5" />
        </bing:Map.Center>
    </bing:Map>
</Button>

Ovviamente lo stile del bottone può essere variato a piacere, qui quello che conta è solo il metodo, che prevede l’incapsulamento del componente Bing Map dentro un bottone, impostando al contempo la proprietà “IsEnabled” della mappa a “false”.

That’s all folks!

Ruby Or Not Ruby

Visto che stanno fiorendo un po’ di post su Ruby, approfitto per dire la mia rispondendo qui al blog di Luca:

Caro Luca, Ruby è una strada molto perigliosa!

Dopo due anni d'uso posso dire che nasconde molte insidie. Specialmente in ambienti dove diversi plugin devono coesistere e devi solo sperare che gli altri siano stati abbastanza educati da non toglierti la sedia sotto il sedere...

Mi spiego: Essendo un linguaggio dinamico, è banale poter ridefinire i metodi di qualsiasi classe anche di base. In particolare, è possibile TOGLIERLI.

Io uso Ruby come linguaggio di programmazione per l'API di  Google SketchUp dove praticamente chiunque può creare dei plugin in ruby. Il che significa che nelle macchine dove viene installato il tuo plugin possono manifestarsi problemi d'uso che non dipendono dal tuo ma da altri plugin "maleducati". In generale questo ti costringe ad una programmazione "estremamente" (ed a mio avviso eccesivamente) difensiva.

Ma vi sono casi in cui alcuni plugin (anche rinomati) fanno uso di librerie altrettanto rinomate (e mi riferisco in particolare ad una libreria molto usata che estende i metodi di datetime) che purtroppo sono bacate, in senso grave, in quanto rimuovono alcuni metodi senza verificare se tali metodi non siano stati eventualmente già rimossi (non ho parole) e visto che in tale caso Ruby genera un errore (e anche qui avrei da ridire, visto che se ti dico di togliere una cosa che non c'è, per lo stile di programmazione tipicamente lasco dei linguaggi dinamici, me lo dovresti tranquillamente ignorare) non c'è difesa.

E' come cucinare la pasta in due in modo indipendente (tu vai in cucina e metti l'acqua a bollire, poi arrivo io a buttare la pasta quando bolle, O VICEVERSA) :
Io posso pure controllare se c'è il sale prima di metterlo nella pentola e se vengo dopo di te va tutto bene. Ma se tu lo metti senza controllare, e vieni DOPO di me, sicuramente mangeremo una pasta molto SALATA...
Questo rischia di crearti un'infinità di problemi che paiono (al cliente) appartenere al tuo plugin...
Io ho risolto perché il cliente ha uno stretto controllo sul parco macchine utilizzate, ma prova a fare un plugin da vendere liberamente... sono cavoli amari. Ciò non significa che non si possano fare, ci sono molti plugin commerciali (ma molti di questi hanno due versioni, una per Mac e una per Win. E visto che esite un'API (obsoleta) per il c++, ho tanto l'idea che molti pezzi siano scritti in c++ ...

Cio non di meno, Ruby ha una sua eleganza e un suo fascino, e ci sono molte storie di successo sviluppate in Ruby On Rail. Ma francamente, se devo usare MVC, io preferisco l'implementazione Microsoft, Visual Studio e .NET è troppo comodo!

Con tutta sincerità, di Ruby ne ho piene le scatole.

Perché la libertà è bellissima e le sue potenzialità infinite, ma la potenza senza il controllo, è niente! (<cit.>). Quando sei libero di fare tutto e quel tutto può nuocere agli altri, nasce l’esigenza di un “corpus” (il più possibilmente piccolo) di regole condivise e di un sistema di controllo e applicazione di quelle regole. Cosicché si è forzatamente meno liberi, ma in cambio si può coesistere pacificamente. E per me questo vale anche nel campo dello sviluppo software.

Buon 2012 !!!

E’ tempo di buoni propositi, e ciascun proponga i suoi!

Ma oltre ai propositi, ovviamente ci sono le previsioni di maghi, astrologhi e illustri sconosciuti, come me!

Ecco dunque le mie:

Quest’anno la vera primadonna sarà WinRT e per questo l’uomo dell’anno sarà il grande Raf, dal quale mi aspetto grandi cose.

Entro la fine dell’anno per ogni 5 smartphone venduti almeno uno sarà un Windows Phone.

E finalmente arriveranno i tablet, di tutte le forme e colori.

Buon anno a tutti!