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

がりらぼ

WindowsRuntimeの応援ブログ

RichTextBlockにバインドする

RichTextBlockとは、読みより用のさまざまなコントロールを置くことのできるTextBlockです。

使い方は、
RichTextBlockのBlocksコレクションにParagraphを追加していくという形になります。

var paragraph = new Paragraph();

            //通常テキスト
            paragraph.Inlines.Add(new Run { Text="リッチ"});
            //改行
            paragraph.Inlines.Add(new LineBreak());

            //このなかにコントロールを入れることができる
            var uiContainer = new InlineUIContainer();
            //ハイパーリンクボタン
            uiContainer.Child = new HyperlinkButton { Content="リンク"};
            paragraph.Inlines.Add(uiContainer);
            richTextBlock.Blocks.Add(paragraph);

Paragraphは、Inlineコレクションを所有しており、通常テキストを描画するRunクラス、さまざまなコントロールを入れることができるUIContainerにコントロールを入れることもできます。
f:id:garicchi:20140120190319p:plain

さて、このRichTextBlockですが、XAMLでプロパティにバインドできません。
通常ならBlocksプロパティにParagraphのコレクションをバインドすればいいはずなのですが、できないんです。

じゃあどうするかというとRichTextBlock自体をバインドしちゃいます。
ContentControlクラスを使うと、Contentプロパティに任意のコントロールを置くことができるのでContentControlにRichTextBlockをバインドするという形をとります。

<Page
    x:Class="BindingRichTextBlock.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:BindingRichTextBlock"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Page.Resources>
        <local:RichTextConverter x:Key="richTextConverter" />
    </Page.Resources>
    <Page.DataContext>
        <local:RichTextModel />
    </Page.DataContext>
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" >
        <ContentControl Content="{Binding RichText,Converter={StaticResource richTextConverter}}" Margin="563,416,610,263" />
    </Grid>
</Page>

バインドするモデル
今回はTextModelというモデルをバインドします。
RichTextModelはPageのDataContextに入る用です。

public class TextModel
    {
        public Uri link { get; set; }

        public string text { get; set; }
    }

    public class RichTextModel
    {
        public TextModel RichText { get; set; }

        public RichTextModel()
        {
            RichText = new TextModel
            {
                link=new Uri("http://garicchi.com"),
                text="がりっち"
            };
        }
    }

これで、ContentControlのContentプロパティにTextModelクラスのインスタンスがバインドされました。
しかし、このままではTextModelクラスがContentプロパティにバインドされていまいますのでRichTextBlockになっていません。
そこで、BindingConverterを作ります。

public class RichTextConverter:IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string str)
        {
            var textModel = value as TextModel;
            var paragraph = new Paragraph();
            var uiContainer = new InlineUIContainer();
            uiContainer.Child = new HyperlinkButton { Content="リンク",NavigateUri=textModel.link};
            paragraph.Inlines.Add(uiContainer);
            paragraph.Inlines.Add(new Run { Text=textModel.text});
            var rich=new RichTextBlock();
            rich.Blocks.Add(paragraph);
            return rich;
        }

        public object ConvertBack(object value, Type targetType, object parameter, string str)
        {
            return null;
        }
    }

バインディング時にConvertメソッドが呼ばれ、value内にTextModelのインスタンスが入っています。
そこで、それこからRichTextBlockを生成し、returnで返してあげることによって、ContentControlのContentプロパティにはRichTextBlockがバインドされるという仕組みです。

サンプル(消すまで掲載します)
garicchi/BindableRichText · GitHub