Windows PhoneアプリのローカリゼーションとApplication BarのBinding #wpjp
この記事はWindows Phone Advent Calendar 2013 - Adventarの18日目の記事です。昨日は@Kera1601さんのPeopleハブの分析と活用 ~Windows Phone Advent Calendar 2013 17日目~ | 高校生のComputer備忘録と考察です。
ドコモメールをWindows Phoneで運用する方法を紹介しようとしたらガラケーユーザーには無理で断念。端末購入にまで至ってる素晴らしい記事があったので紹介。
断念に至ったメモは下記にて。こちらのメモ記事でも上記リンクを結論として紹介させて頂きました。
そして持ってたソースを漁ってひねり出した下記のテーマ(無計画
Windows Phoneアプリのローカリゼーション
いまどきのスマートフォンアプリは多言語対応されていることが多いかと思います。Windows Phoneでも多い話題ですがおさらいです。
プロジェクトテンプレートが色々と準備済みなので、プロジェクトを作成したらMainPage.xamlの指示に従うだけです。
<!-- ローカライズに関する注: 表示された文字列をローカライズするには、その値を、アプリのニュートラル言語 リソース ファイル (AppResources.resx) 内の適切な名前のキーにコピーしてから、 属性の引用符間のハードコーディングされたテキスト値を、パスがその文字列名を 指しているバインド句と置き換えます。 例: Text="{Binding Path=LocalizedResources.ApplicationTitle, Source={StaticResource LocalizedStrings}}" このバインドは、テンプレートの "ApplicationTitle" という文字列リソースを指します。 [プロジェクトのプロパティ] タブでサポートされている言語を追加すると、 新しい resx ファイルが、UI 文字列の翻訳された値を含む言語ごとに作成 されます。これらの例にあるバインドにより、属性の値が、実行時に アプリの CurrentUICulture と一致する .resx ファイルから描画されます。 -->
まずはプロジェクトのプロパティで言語を追加します。すると、resxファイルが作成されますので、同じキーでそれぞれの言語のリソースを定義します。
あとはデータバインドするだけです。簡単!*1
実行するとresxで指定した文字列がバインドされています。端末の設定で言語を変えて再起動するとサポートしてる言語に切り替わります。
Application BarのBinding
さて唐突にApplication Barの話になりましたが、実はApplication Barはバインドが使えないので実行時にコードビハインドからインスタンスを生成して挿入する必要があり面倒です。バインドが使える時の簡単さはこの記事でもご覧になった通りなので是非バインドさせたいですよね。
やり方は簡単で、バインド出来ないプロパティにはよく使う(?)テクニックです。バインド可能なプロパティを持ったビヘイビアーを作成して、ビヘイビアーから変更を同期させます。
……が、問題があってApplication Barにビヘイビアーを設定できないのでPhoneApplicationPage用のビヘイビアーを作成します。
public class BindToApplicationBarIconButtonBehavior : Behavior<PhoneApplicationPage> { /// <summary> /// テキストを取得または設定します。 /// </summary> public string Text { get { return (string)GetValue(TextProperty); } set { SetValue(TextProperty, value); } } public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(BindToApplicationBarIconButtonBehavior), new PropertyMetadata(TextChangedHandler));
この時、どのボタンにバインドさせるかを指定する必要があるのでp&p prismを参考にTextで特定させてみます。*2
void ChangeText() { if (this.Text == null) throw new InvalidOperationException("Text が設定されていません。"); var buttons = this.AssociatedObject.ApplicationBar.Buttons .OfType<ApplicationBarIconButton>() .Where(x => x.Text == this.TargetItemStaticText); if (!buttons.Any()) throw new InvalidOperationException("TargetItemStaticText が一致するボタンが見つかりません。"); if (buttons.Count() > 1) throw new InvalidOperationException("他のアイテムと同じテキストを設定することはできません。"); buttons.First().Text = this.Text; this.TargetItemStaticText = this.Text; }
あとはxamlでこんな風にボタンのTextとビヘイビアーの特定用Textを一致させます。
<phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True"> <shell:ApplicationBar.MenuItems> <shell:ApplicationBarMenuItem Text="MenuItem 1"/> <shell:ApplicationBarMenuItem Text="MenuItem 2"/> </shell:ApplicationBar.MenuItems> <shell:ApplicationBarIconButton IconUri="/Assets/AppBar/add.png" Text="1"/> <shell:ApplicationBarIconButton IconUri="/Assets/AppBar/delete.png" Text="2"/> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> <i:Interaction.Behaviors> <local:BindToApplicationBarIconButtonBehavior TargetItemStaticText="1" Text="{Binding LocalizedResources.AppBarButton_Add, Mode=OneWay, Source={StaticResource LocalizedStrings}}"/> </i:Interaction.Behaviors>
実行すると"1"に設定したボタンがバインディングされ、無事に完了です。
ビヘイビアーのソースはgistにあげました。埋め込むと長くなるのでリンク置いときます。