RichTextBox for WPF
スタイルのオーバーライド
RichTextBox for WPF の使い方 > スタイルのオーバーライド

構文の色指定」では、C1TextRange オブジェクトを使用し、選択範囲を移動することなくドキュメントの一部分のスタイルを変更する方法について説明しました。ただし、ドキュメント自体ではなく、ビューのみを変更する必要がある場合もあります。

たとえば、現在の選択範囲は、異なる前景色と背景色で強調表示されます。これは、ドキュメント自体ではなくビューに属するスタイルの変更です。他の例としては、構文の色指定や入力中のスペルチェックがあります。

C1RichTextBox コントロールは、StyleOverrides プロパティを使用してこのようなシナリオをサポートします。このプロパティには、ビューにのみ適用される範囲とスタイルの変更を指定するためのオブジェクトのコレクションが含まれます。この方法には、前のセクションで行った C1TextRange オブジェクトにスタイルの変更を適用する方法に比べて、次の2つのメリットがあります。

この方法には、ドキュメントフローに影響するスタイル要素をスタイルの変更に入れることができないという制限があります。スタイルのオーバーライドを使用して、背景や前景を変更したり、ドキュメントの一部に下線を引くことができます。ただし、フォントのサイズやスタイルの変更は、ドキュメントフローに影響する可能性があるので実行できません。

ここでは、前の構文の色指定の例をスタイルのオーバーライドの使用例に変えて示します。

まず、C1RangeStyleCollection オブジェクトを宣言し、これをコントロールの StyleOverrides コレクションに追加する必要があります。これで、コレクションに追加されたすべてのオーバーライドがコントロールに適用されるようになります。後で、ドキュメントの構文の色指定部分をコレクションに挿入します。

コードのコピー
Private _rangeStyles As New C1RangeStyleCollection()
Public Sub New()
   InitializeComponent()
   _rtb = New C1RichTextBox()
   LayoutRoot.Children.Add(_rtb)
   AddHandler _rtb.TextChanged, AddressOf tb_TextChanged
   _rtb.FontFamily = New FontFamily("Courier New")
   _rtb.FontSize = 16
   _rtb.Text = GetStringResource("w3c.htm")
   ' C1RangeStyleCollection をコントロールの
   ' StyleOverrides コレクションに追加します
   _rtb.StyleOverrides.Add(_rangeStyles)
End Sub
コードのコピー
C1RangeStyleCollection _rangeStyles = new C1RangeStyleCollection();
public MainPage()
{
InitializeComponent();
_rtb = new C1RichTextBox();
LayoutRoot.Children.Add(_rtb);
_rtb.TextChanged += tb_TextChanged;
_rtb.FontFamily = new FontFamily("Courier New");
_rtb.FontSize = 16;
_rtb.Text = GetStringResource("w3c.htm");
// C1RangeStyleCollection をコントロールの
// StyleOverrides コレクションに追加します
_rtb.StyleOverrides.Add(_rangeStyles);
}

ここで必要なことは、以前に示した UpdateSyntaxColoring メソッドを変更して、(以前のようにドキュメントに色指定を適用する代わりに)そこでコレクションに範囲スタイルを挿入します。

コードのコピー
' StyleOverrides コレクションを使用して構文を色指定します
' (デフォルトドキュメントの強調表示には数分の1秒かかります)
PrivateSub UpdateSyntaxColoring(ByVal rtb As C1RichTextBox)
' HTML の解析に使用される正規表現を初期化します
String pattern =
   "</?(?<tagName>[a-zA-Z0-9_:\-]+)" +
   "(\s+(?<attName>[a-zA-Z0-9_:\-]+)" +
   (?<attValue>(\s*=\s*""(^"")+"")?))*\s*/?>"
' ドキュメントの色指定に使用されるスタイルを初期化します
Dim key As var =C1TextElement.ForegroundProperty
Dim brDarkBlue As var =New C1TextElementStyle()
brDarkBlue(key) = New SolidColorBrush(Color.FromArgb(255, 0, 0, 180))
Dim brDarkRed As var =New C1TextElementStyle()
brDarkRed(key)= New SolidColorBrush(Color.FromArgb(255, 180, 0, 0))
Dim brLightRed As var =New C1TextElementStyle()
brLightRed(key) = New SolidColorBrush(Colors.Red)
' 以前の色指定を削除します
_rangeStyles.Clear()
' 一致を強調表示します
Dim input As var =rtb.Text
Dim m As Match
For Each m In Regex.Matches(input,pattern)
  ' タグ全体を選択して濃い青色にします
   Dim range As var =rtb.GetTextRange(m.Index,m.Length)
   _rangeStyles.Add(New C1RangeStyle(range,brDarkBlue))
   ' タグ名を選択して濃い赤色にします
   Dim tagName As var =m.Groups("tagName")
   range = rtb.GetTextRange(tagName.Index, tagName.Length)
   _rangeStyles.Add(New C1RangeStyle(range,brDarkRed))
   ' 属性名を選択して明るい赤色にします
   Dim attGroup As var =m.Groups("attName")
   If Not attGroup Is Nothing Then
     Dim att As Capture
     For Each att In attGroup.Captures
       range = rtb.GetTextRange(att.Index, att.Length)
       _rangeStyles.Add(New C1RangeStyle(range,brLightRed))
     Next
   End If
Next
End Sub
コードのコピー
// StyleOverrides コレクションを使用して構文を色指定します
// (デフォルトドキュメントの強調表示には数分の1秒かかります)
void UpdateSyntaxColoring(C1RichTextBox rtb)
{
// HTML の解析に使用される正規表現を初期化します
string pattern =
   @"</?(?<tagName>[a-zA-Z0-9_:\-]+)" +
   @"(\s+(?<attName>[a-zA-Z0-9_:\-]+)" +
   (?<attValue>(\s*=\s*""[^""]+"")?))*\s*/?>";
// ドキュメントの色指定に使用されるスタイルを初期化します
var key = C1TextElement.ForegroundProperty;
var brDarkBlue= new C1TextElementStyle();
brDarkBlue[key] = new SolidColorBrush(Color.FromArgb(255, 0, 0, 180));
var brDarkRed  = new C1TextElementStyle();
brDarkRed[key]= new SolidColorBrush(Color.FromArgb(255, 180, 0, 0));
var brLightRed= new C1TextElementStyle();
brLightRed[key] = new SolidColorBrush(Colors.Red);
// 以前の色指定を削除します
_rangeStyles.Clear();
// 一致を強調表示します
var input = rtb.Text;
foreach (Match m in Regex.Matches(input, pattern))
{
  // タグ全体を選択して濃い青色にします
   var range = rtb.GetTextRange(m.Index, m.Length);
   _rangeStyles.Add(new C1RangeStyle(range, brDarkBlue));
  // タグ名を選択して濃い赤色にします
   var tagName = m.Groups["tagName"];
   range = rtb.GetTextRange(tagName.Index, tagName.Length);
   _rangeStyles.Add(new C1RangeStyle(range, brDarkRed));
  // 属性名を選択して明るい赤色にします
   var attGroup = m.Groups["attName"];
   if (attGroup != null)
   {
     foreach (Capture att in attGroup.Captures)
     {
       range = rtb.GetTextRange(att.Index, att.Length);
       _rangeStyles.Add(new C1RangeStyle(range, brLightRed));
     }
   }
}
}

変更されたコードは、元のコードとほとんど同じです。ドキュメントの色指定のためのブラシを作成する代わりに、前景のプロパティをオーバーライドした C1TextElementStyle オブジェクトを作成します。このコードは、最初にオーバーライドコレクションをクリアし、次に正規表現を使用してドキュメント内の各 HTML タグの場所を特定し、最後に範囲を C1TextElementStyle オブジェクトに関連付ける C1RangeStyle オブジェクトをオーバーライドコレクションに挿入します。

この新しいコードを実行すると、パフォーマンスが格段に向上していることがわかります。新しいコードは、元のコードより数千倍高速です。