2015年5月20日水曜日

WPFのRichTextBoxで文字数を制限する

※ 疑最適解の謎ポストですお許しを WPFでアプリケーションを作っていて、トレースログをUI上に表示する機能が必要なことが結構あります。ほとんどの人はそんなことないと思いますが、私にはあります。
そしてトレースログなのでERRORとかWARNINGとかINFOとか表示するので、漢の私は赤とかオレンジとかボールドとか使って味気ないログを華やかに彩りたいと思うのです。
するとUIにはTextBoxコントロールではなくRichTextBoxコントロールを使わなければいけないのですが、ここで問題が。
そんなに過去のトレースログをご丁寧に画面上のコントロールに持っておくのも精神衛生上よろしくないので文字数に制限をかけたいと考えるのですが、WPFのRichTextBoxにはないんですね、MaxLengthプロパティが。
ですが DeleteTextInRun というメソッドがあるようなので、これを使えば打ち止めの文字数を超えたN文字を先頭から削除するのはちょちょいのちょいだよね・・・

MyRichTextBox.Document.ContentStart.DeleteTextInRun(N);

働きませんな。
何が間違っているのでしょうか、私はダメな人間でしょうか。
そこでGoogle先生に DeleteTextInRun doesn't work と質問したところ海外のQuiitaことStackoverflowやMSDNでも似たようなことでお困りの方が何人かおられましたが、私の求める最適解にはたどり着けませんでした。
しかたないので参考になる文献をベースに修正してTextChangedイベントに実装した結果

private void MyRichTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
    // MaxTextLengthは制限をかけたい文字数です
    TextRange range = new TextRange(MyRichTextBox.Document.ContentStart, MyRichTextBox.Document.ContentEnd);     if (range.Text.Length > MaxTextLength)     {         TextSelection selection = MyRichTextBox.Selection;         TextPointer contentStart = MyRichTextBox.Document.ContentStart;         TextPointer selectionStart = contentStart.GetPositionAtOffset(0);         TextPointer selectionEnd = contentStart.GetPositionAtOffset(range.Text.Length - MaxTextLength);         selection.Select(selectionStart, selectionEnd);         selection.Text = "";     } }

期待する動きは実現しましたがかなり冗長な気がするんです。
いい方法をご存知の方、居たら教えてください。