Technology Experience
.NET World

Usare WPF Localization Extension con un ContextMenu definito nelle risorse di una Window

Mi è stato chiesto di sviluppare uno UserControl WPF multilingua, quindi in grado di switchare sia a design-time che a run-time da una lingua all’altra. Ovviamente mi sono buttato subito sull’extension WPF Localization Extension. Direi che è semplice da utilizzare (una volta capiti bene i suoi meccanismi) e fa quello che promette. Supporta il passaggio da una lingua all’altra a run-time, supporta una lingua da visualizzare a design-time, ed è facile aggiungere nuove lingue, dal momento che è sufficiente creare un nuovo file di risorse dedicato alla nuova lingua.

Do per scontato che sappiate già utilizzare questa extension. Supponiamo di avere una Window definita come segue:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:lex="http://wpflocalizeextension.codeplex.com"
        lex:LocalizeDictionary.DesignCulture="en-US"
        lex:ResxLocalizationProvider.DefaultAssembly="WpfApplication1"
        lex:ResxLocalizationProvider.DefaultDictionary="Strings"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Button Content="{lex:Loc Ok}" Width="100" Height="30" />
    </Grid>
</Window>

Qui si instanzia il WPF Localization Extension, dicendo che la culture a design-time è “en-US”, che le risorse sono contenute nell’assembly “WpfApplication1” e che i file di risorse si chiamano “Strings.resx” (e di conseguenza Strings.it-IT.resx, Strings.fr-FR.resx, e via dicendo).

Il problema nasce quando si vuole definire un ContextMenu nelle risorse della Window. D’istinto verrebbe da scrivere il seguente codice XAML:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:lex="http://wpflocalizeextension.codeplex.com"
        lex:LocalizeDictionary.DesignCulture="en-US"
        lex:ResxLocalizationProvider.DefaultAssembly="WpfApplication1"
        lex:ResxLocalizationProvider.DefaultDictionary="Strings"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <ContextMenu x:Key="m">
            <MenuItem Header="{lex:Loc Menu1}" />
            <MenuItem Header="{lex:Loc Menu2}" />
            <MenuItem Header="{lex:Loc Menu3}" />
        </ContextMenu>
    </Window.Resources>
    <Grid>
        <Button Content="{lex:Loc Ok}"
                ContextMenu="{StaticResource m}"
                Width="100" Height="30" />
    </Grid>
</Window>

In pratica, abbiamo aggiunto un ContextMenu con x:Key=”m”, e lo si utilizza all’interno del Button. Peccato che il WPF Localization Extension non sia in grado di trovare le stringhe localizzate. Ve ne accorgete perchè invece di vedere la stringa prelevata dal vostro file di risorsa, trovate la stringa “Key:Menu1” (vado a memoria), segno inequivocabile che qualcosa è andato storto. E’ vero quello che ho appena scritto? Non proprio. Va sempre bene utilizzare la markup extension {lex:Loc}, ma va utilizzata una sintassi differente, che è la seguente:

<ContextMenu x:Key="m">
    <MenuItem Header="{lex:Loc WpfApplication1:Strings:Menu1}" />
    <MenuItem Header="{lex:Loc WpfApplication1:Strings:Menu2}" />
    <MenuItem Header="{lex:Loc WpfApplication1:Strings:Menu3}" />
    <MenuItem Header="{lex:Loc WpfApplication1:Strings:Menu4}" />
    <MenuItem Header="{lex:Loc WpfApplication1:Strings:Menu5}" />
</ContextMenu>

Non ho trovato una documentazione ufficiale (ma io con i motori di ricerca, si sa, non sono bravissimo), ma direi che la sintassi sia: <namespace>:<file_di_risorsa:<chiave>. Strana sintassi, perchè bisogna separare ogni parte con un “:”, come si vede dallo stralcio di XAML qui sopra.

Et voilà, il gioco è fatto! Così il ContextMenu viene correttamente popolato con le traduzioni prese dal file di risorsa, traduzioni che cambiano anche a run-time nel caso in cui switchate da una lingua all’altra programmaticamente agendo sull’oggetto singleton LocalizeDictionary.

Send to Kindle

Igor Damiani

La sua passione per l'informatica nasce nella prima metà degli anni '80, quando suo padre acquistò un Texas Instruments TI-99. Da allora ha continuato a seguire l'evoluzione sia hardware che software avvenuta nel corso degli anni. E' un utente, un videogiocatore ed uno sviluppatore software a tempo pieno. Igor ha lavorato e lavora anche oggi con le più moderne tecnologie Microsoft per lo sviluppo di applicazioni: .NET Framework, XAML, Universal Windows Platform, su diverse piattaforme, tra cui spiccano Windows 10 piattaforme mobile. Numerose sono le app che Igor ha creato e pubblicato sul marketplace sotto il nome VivendoByte, suo personale marchio di fabbrica. Adora mantenere i contatti attraverso Twitter e soprattutto attraverso gli eventi delle community .NET.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.