[WPF][C#]RichTextBoxに文書をBindする方法

1.)はじめに

HTMLを簡易表示するため、Webブラウザコントロールではなく、RTFを使用できるRichTextBoxを使用した時に困ったことになりました。
RichTextBoxはテキスト文字列のBindができませんでした。ネットで調べているといくつか対応方法が公開されていました。
今回は、CodeProjectの記事を参考にRichTextBoxにデータをバインドする方法を紹介します。
BindableRichTextBox.jpg

2.)対応方法

RichTextBoxのプロパティDocumentはDependencyPropertyが無く、データバインディングができません。
そこで、RichTextBox から派生させた BindableRichTextBox クラスを 定義します.
Document プロパティを改めて定義し直し,Documentプロパティが変更されたら RichTextBox クラスとしてのDocument プロパティに渡すようにします。
    public class BindableRichTextBox : RichTextBox
    {
        public static readonly DependencyProperty DocumentProperty =
            DependencyProperty.Register("Document", typeof(FlowDocument),
            typeof(BindableRichTextBox), new FrameworkPropertyMetadata
            (null, new PropertyChangedCallback(OnDocumentChanged)));

        public new FlowDocument Document
        {
            get
            {
                return (FlowDocument)this.GetValue(DocumentProperty);
            }

            set
            {
                this.SetValue(DocumentProperty, value);
            }
        }

        public static void OnDocumentChanged(DependencyObject obj,
            DependencyPropertyChangedEventArgs args)
        {
            RichTextBox rtb = (RichTextBox)obj;
            rtb.Document = (FlowDocument)args.NewValue;
        }
    }
これだけでは、string型のRTF文書をBindすることができません。
そこで以下のようなConverterを作成します。
    /// 
    /// rtf文字列をFlowDocumentに変換する
    /// 
    [ValueConversion(typeof(FlowDocument), typeof(string))]
    public class RtfDocumentConverter : IValueConverter
    {
        public object Convert(object value, Type targetType,
            object parameter, System.Globalization.CultureInfo culture)
        {
            //http://saitx.wordpress.com/2010/03/18/handling-rtf-textbox-in-wpf/
            FlowDocument flowDocument = new FlowDocument();
            string rtf = value as string;
            using (MemoryStream ms = new MemoryStream())
            {
                using (StreamWriter sw = new StreamWriter(ms))
                {

                    TextRange range = new TextRange(flowDocument.ContentStart, flowDocument.ContentEnd);
                    sw.Write(rtf);
                    sw.Flush();
                    ms.Seek(0, SeekOrigin.Begin);
                    range.Load(ms, DataFormats.Rtf);
                }
            }

            return flowDocument;
        }
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return null;
        }
    }
これらのコードを使用して以下のようにXAMLを記載します。
<r:BindableRichTextBox x:Name="rich" IsDocumentEnabled="True" IsReadOnly="True" Document="{Binding Path=text, Converter={StaticResource rtfDocumentConverter}}" Hyperlink.Click="rich_Click"/&rt;
これで、RTF文書をRichTextBoxにBindingすることができます。

3.)サンプルコード

BindableRichTextBox.zip


0 件のコメント :

コメントを投稿