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

亀岡的プログラマ日記

京都のベッドタウン、亀岡よりだらだらとお送りいたします。

SilverlightのListBoxでつくるいんちきHorizontalTextBlock

C# Silverlight

この記事は、Silverlight Advent Calenderの9日目です。

Silverlightで縦書きテキストボックス作りたいよね!!特にWP7ではロック画面が素敵な縦書き表示なのになんだかなあという感じです。
てなわけで、縦書きテキストボックスですが。


。。。えぇ、車輪の再発明なのことは重々承知していますとも!しかも2年も前の。

とはいえ、オリジナリティ出すために、ちょっと小細工を入れてますので、まぁ、お目こぼしを・・・。

まず構造ですが、ListBoxを二重で重ねています。
①ListBox→②ItemsTemplateにさらにListBox→③TextBlockに一文字一文字ほうりこむ、です。
まず、①のListBoxにおけるItemsPanelテンプレートを触ることで、通常の上から下への表示を変更できます、こんな感じに。

 	<ItemsPanelTemplate x:Key="HorizontalTextListPanelStyle">
            <StackPanel Orientation="Horizontal" FlowDirection="RightToLeft" />
        </ItemsPanelTemplate>


それから、①のListBoxのItemTemplateを、以下のように内部にListBoxを囲むような形にしてやります。

	<DataTemplate x:Key="HorizontalTextBlockDataTemplate">
            <ListBox Background="{x:Null}" BorderBrush="{x:Null}" ItemsSource="{Binding Characters}" ItemContainerStyle="{StaticResource HorizontalTextBlockCharContainerTemplate}" ItemTemplate="{StaticResource HorizontalTextLineTemplate}" Style="{StaticResource HorizontaTextBlockStyle}"/>
	</DataTemplate>


後はさらにその中のItemTemplateを以下のようにしてやります。

	<DataTemplate x:Key="HorizontalTextLineTemplate">
            <TextBlock Text="{Binding Charcter}" RenderTransformOrigin="0.5,0.5">
                <TextBlock.RenderTransform>
                    <CompositeTransform TranslateX="{Binding LeftMargin}" TranslateY="{Binding TopMargin}" Rotation="{Binding Rotate}"/>
                </TextBlock.RenderTransform>
            </TextBlock>
	</DataTemplate>

さて、なんでRenderTransformかけてるのかといいますと、このItemTemplateにバインディングされるのはただの文字データではなく、LeftMargin, TopMargin, Rotateという3つのプロパティを持った文字型ラップクラスを作っています。

なんのためにかというと、「ぁ」とか「っ」とか「〜」とか「、」に対処する為ですね!!こんな力技で!!

        public static readonly List<char> smallChars = "ぁぃぅぇぉっァィゥェォッゃャゅュょョ".ToList();
        public static readonly List<char> punctuation = "。、.,".ToList();
        public static readonly List<char> rotateChars = "ーー〜…".ToList();

        public StringCharacter(char charcter, FontFamily family, double fontSize)
        {
            // 頑張って大きさ測定
            var measureTb = new TextBlock();
            measureTb.Text = charcter.ToString();
            measureTb.FontFamily = family;
            measureTb.FontSize = fontSize;
            _size = new Size(measureTb.ActualWidth, measureTb.ActualHeight);
            _charcter = charcter;
      //小文字をずらす
            if (smallChars.Contains(_charcter))
            {
                LeftMargin =  _size.Height / 8.0;
                TopMargin = -_size.Height / 8.0;
            }
      //句読点はずらし幅が違う・・・
            if (punctuation.Contains(_charcter))
            {
                LeftMargin = _size.Height / 3.0;
                TopMargin = -_size.Height / 3.0;
            }
      //伸ばし棒はぐるっと回す
            if (rotateChars.Contains(_charcter))
            {
                Rotate = 90;
            }
        }

うん、清々しいくらいの力技ですね。ああ石を投げないで・・・
てなわけで、こんな感じで表示できます。やれやれ。

f:id:posaunehm:20111210000352j:image