読者です 読者をやめる 読者になる 読者になる

tmytのらくがき

個人の日記レベルです

ContextMenuの中華フォント問題

ToolkitのContextMenuを使うと中国語フォントで表示されます。id:ch3cooh393がContextMenuに関するエントリをしていたので、せっかくなので僕もContextMenuの話をしようと思います。

日本語が中国語のフォントで表示されてしまう問題はロケールを正しく設定することで回避ができます。

ようは、ページごとに設定するのではなくその上位のFrameで設定すればいいという話。WPFSilverlightは上位の設定を引き継ぎますからね。

各国のUIフォントに対するためのより簡単な対応方法 - 高橋 忍のブログ - Site Home - MSDN Blogs

つまりRootFrameのLanguageプロパティを正しく設定すればいいよね!っていうことでした。

しかしContextMenuはRootFrameからLanguageを正しく読んでくれません。たぶん添付プロパティ経由でコントロールが生成されるのでRootFrameから継承しないんでしょうね。なので、RootFrameにいくらLanguage="ja-jp"なコードを付けたそうと、実行すると次のような表示になってしまいます。

今回書いたXAMLは次の通り。

<Button>
    <toolkit:ContextMenuService.ContextMenu>
        <toolkit:ContextMenu>
            <toolkit:MenuItem Header="花直忍" />
        </toolkit:ContextMenu>
    </toolkit:ContextMenuService.ContextMenu>
</Button>

このContextMenuにLanguage属性を設定すると正しく日本語フォントで表示されます。

しかしこれもまたあれです。言語決めうちなので美しく無い。というわけで僕からの解決方法を2つ。

ひとつめ。ラッパークラスを作ってそこで言語を適切に設定する方法。
次のようなクラスを作ります。

using System.Globalization;
using System.Windows.Markup;
using Microsoft.Phone.Controls;

namespace PhoneApp2
{
    public class LocalizedContextMenu : ContextMenu
    {
        public LocalizedContextMenu()
            : base()
        {
            Language = XmlLanguage.GetLanguage(CultureInfo.CurrentUICulture.Name);
        }
    }
}

そしてこのクラスを使ってコンテキストメニューを記述します。

<Button>
    <toolkit:ContextMenuService.ContextMenu>
        <my:LocalizedContextMenu>
            <toolkit:MenuItem Header="花直忍" />
        </my:LocalizedContextMenu>
    </toolkit:ContextMenuService.ContextMenu>
</Button>

名前空間は適切に追加してください。これだけで正しい言語を参照するようになります。

そしてふたつめ。Silverlight Toolkit自体を改造してしまう方法。
こっちの方法だと改造しないといけないですが、サンプルのコードコピペだけで使えるようになります。とりあえずRootFrameのLanguageを参照するように改造してみます。
Silverlight for Windows Phone Toolkitのソースコードを取得して、Microsoft.Phone.Controls.Toolkit\ContextMenu\ContextMenu.csを開いて、その中のInitializeRootVisual関数を編集します。

private void InitializeRootVisual()
{
    if (null == _rootVisual)
    {
        // Try to capture the Application's RootVisual
        _rootVisual = Application.Current.RootVisual as
            PhoneApplicationFrame;
        if (null != _rootVisual)
        {
            _rootVisual.MouseMove -= OnRootVisualMouseMove;
            _rootVisual.MouseMove += OnRootVisualMouseMove;

            _rootVisual.ManipulationCompleted -= OnRootVisualManipulationCompleted;
            _rootVisual.ManipulationCompleted += OnRootVisualManipulationCompleted;

            _rootVisual.OrientationChanged -= OnEventThatClosesContextMenu;
            _rootVisual.OrientationChanged += OnEventThatClosesContextMenu;

            // この行を追加
            Language = _rootVisual.Language;
        }
    }
}

これでRootVisualの言語を参照するようになりました。あとはビルドして普段使ってるToolkitと差し替えるだけです。

どっちのやり方がいいかというのは微妙な上に、どちらにしろだいぶ面倒ですがこれをやっておくとアプリケーションのコンテキストメニューも美しくなっておすすめです。