RichTextBox とデータバインディングする

Visual Studio とかでは当たり前のように表示されている出力ウィンドウのような部分で使われているのは
おそらく RichTextBox に類するものではないかと思っています.
テキストの種類によって色を変えたり太さを変えたりしてますよね.
自分のソフトでも同じようなものを実現しようとすると,
WPF では RichTextBox を使いたくなります.
RichTextBox は XAML 上では次のように使うようです.

Document プロパティは FlowDocument クラスのようで,
その下に Paragraph を並べることで文章を表示するようです.

じゃあ MVVM で RichTextBox の中身をデータバインディングしてほげほげしましょ.
と調子に乗って Document にバインドしようとすると次のように怒られてしまいました.
DisBindable
Document プロパティは DependencyProperty ではないようで,
このままではデータバインディングできないようです.

そこで CodePlex かどこかで紹介されていたネタがこちら.

DependencyProperty ではないのなら DependencyProperty にすればいいじゃない!
というわけで RichTextBox から派生させた BindableRichTextBox クラスを 定義します.
Document プロパティを改めて定義し直し,
Document プロパティが変更されたら RichTextBox クラスとしての Document プロパティに横流ししています.

さらに,このまま FlowDocument としてデータバインドするのもいいんですが,
出力ウィンドウのようなものを考えた場合,
もう少し情報量を制限したものとバインドしたほうがやりやすいと思うので,
次のようなクラスを作ります.

文字列を格納する Text プロパティと,
それを修飾するための Foreground プロパティと FontWeight プロパティ.
それから行間を決める Margin プロパティです.
このクラスのコレクションをバインドして,
あとはコンバータで FlowDocument に変換させます.

こうすることで例えば ObservableCollection<RichTextItem> 型の OutMessage プロパティを用いて

というような感じで Document プロパティにバインドできる RichTextBox ができあがります.
BindableRichTextBox
上の画像は Add ボタンでその上の TextBox の内容をランダムな色で追加するというもので,
10 行目を追加したところ.
後は自動的に末尾にスクロールさせたりとかすれば,
出力ウィンドウの再現もそう遠くはないはず.