WPF 対応のテキストエディタコントロール

Last Updated 2012/08/24


WPF 対応のテキストエディタコントロールが公開されました。私が作ったものではありませんが、ご紹介します。使い始めてまだ間がないので、明確な評価はできませんが、実用的に使えると思います。


私は数年前に .NET Framework 対応のテキストエディタを作りかけたことがありますが、WPF が UI の主流になることが確実になったことから開発を中断していました。その後、そろそろ誰かが作っているのではと思い、WEB サイトを探したところ、ありました。しかも十分使えるレベルにあります。

コントロールの名前は AvalonEdit ですが、これは通称です。テキストエディタ本体のクラス名は TextEditor クラスだからです。

Note 通称といいましがが、そうだと宣言されているわけではありません。もともとも、Avalon は WPF の開発コードだったそうです。したがって、AvalonEdit は WpfEdit でもよかったといえそうです。

AvalonEditは、開発ツールのページで紹介した SharpDevelop の一部としてのコードエディタとして作られたものですが、単独のテキストエディタコントロールとして使うことができます。

私は、テキストエディタの機能として最低限これだけはほしいと考えていたことがあります。まず、それをリストアップします。

AvalonEdit はこれらの条件をすべて満足します。ただし、決定的な欠点があります。これについては後述します。また、その解決策についても示します。


AvalonEdit の入手先

AvalonEdit は次のサイトからダウンロードできます。ファイルは、DLL ファイルとそのテスト用アプリケーション、ソースコード、CHM 形式のヘルプファイルの 3 つに分かれています。

Using AvalonEdit (WPF Text Editor)
Note 上記の AvalonEdit のバージョンは、4.2 ですが、2012 年 7 月 30 日付けで SharpDevelop 4.3 が公開されました。この中に含まれる AvalonEdit のバージョンも 4.3 です。http://build.sharpdevelop.net/BuildArtefacts/ からダウンロードできます。ただし、ヘルプファイルを含みません。

ヘルプファイルはフリーウエアソフトにありがちな手抜きがありますので、ほとんど役に立ちません。しかし、クラスの構成などを見るには必要です。ソースコードが付いていますから詳しい内容はソースコードを解読することになります。

ソースコードを解読と言いましたが、暗号の解読と同じです。このコントロールの作者はクラスを細かく分けるのが好みのようで、どこがどうつながっているかを理解するのは至難なワザです。あまり深入りしないことをおすすめします

上記の ZIP ファイルに同梱のテスト用アプリケーションについて、補足しておきます。フォームの右側にあるのはテキストエディタコントロールのプロパティエディタです。サイズを大きくし、[Options] の中にある ShowEndOfLines プロパティを true の設定すると改行マークが表示されます。また、[TextEditor] の WordWrap プロパティを true にするとテキストを折り返します。

Note アプリケーションにツールバーを付けたのですからせめて ToolTip を設定しておいてくれれば助かるのですが、面倒だったのでしょうか。

文字コード

AvalonEdit のデフォルトの文字コードは utf-8 です。これは WPF の標準ですから当然ですね。最近は utf-8 を使う人が多くなりましたが、過去に作ったテキストファイルは shift-jis が大勢です。したがって、shift-jis のファイルを読み込む機能は必須です。AvalonEdit はファイルからテキストを読み込むとき、文字コードを自動的に判定する機能を持っています。shift-jis のファイルも正しく読み込み、保存するときは shift-jis のまま保存されます。


テキストの折り返し

コードエディタであればテキストを折り返す必要はありませんが、テキストエディタではテキストを折り返す機能は必須です。TextEditor クラスの WordWrap プロパティに true を設定するとテキストを折り返すモードになります。

禁則処理

テキストを折り返しモードにすると、問題になるのがいわゆる禁則処理です。禁則処理とは句読点が行の先頭にこないようにするとか、開くかっこが行の末尾にこないように調整することです。AvalonEdit はどういうわけか禁則処理を行っています。少なくとも、そのようにみえます。これはチョットしたおどろきでした。

日本語版 WPF の FormattedText クラスは実用レベルの禁則処理をサポートしますからそのせいかもしれません。


改行マーク

アメリカ人は気にしないのかもしれませんが、改行マークの表示は絶対にほしい機能です。

TextEditor クラスの Options プロパティから参照する TextEditorOptions クラスの ShowEndOfLine プロパティに true を設定すると改行マークを表示します。なお、改行マーク用文字はソースコードを直接手を加えることで変更可能です。次の「特殊記号の表示」でその手順を説明します。

特殊記号の表示

特殊記号とは以下のとおりです。

記号表示関連するプロパティ
改行マーク0x00B6TextEditorOptions クラスの ShowEndOfLine プロパティ
空白0x00B7同、ShowSpaces プロパティ
[Tab]0x00BB同、ShowTabs プロパティ
制御文字矩形で囲む同、ShowBoxForControlCharacters プロパティ

制御文字は ASCII コードの 32 未満の文字です。テキストエディタの中で使う機会はほぼないと思いますが、かつては使っていたことがあります。たとえば、0x0C は "Form Feed" を意味し、印刷時にこの文字がある位置で改ページします。AvalonEdit ではこれを表示するとき、"FF" と表示し、文字のまわりを矩形で囲むことができます。

さて、空白と [Tab] を表示する文字は次のファイルの中に埋め込まれています。別の文字に変えたい場合はソースコードを変更してください。

  AvalonEdit_Source\ICSharpCode.AvalonEdit\Rendering\SingleCharacterElementGenerator.cs

改行マークのほうは次のファイルにあります。日本語対応のテキストエディタの多くは改行マークとして下向き矢印を使うケースが多いようです。もしそうしたければ、0x00B6 を 0x2193 に変えるといいでしょう。

  AvalonEdit_Source\ICSharpCode.AvalonEdit\Rendering\NewLineElementGenerator.cs

特殊記号の文字色

前項では、特殊記号をあらわす文字を変更する手順を説明しました。次は特殊記号の文字色を任意の色に設定する手順です。

これらの文字色は ICSharpCode.AvalonEdit.Rendering.TextView クラスの NonPrintableCharacterBrush プロパティで設定できます。デフォルトは Brushes.LightGray です。このプロパティを分離コードで設定する手順は以下のとおりです。

  textEditor.TextArea.TextView.NonPrintableCharacterBrush = Brushes.Red;

改行文字の変数化

上記の手順では、改行文字をハードコードすることになり、ユーザーの好みに合うかどうかは分かりません。そこで、それを変数化する手順を説明します。

まず、TextEditorOptions クラスに NewLine プロパティを追加します。

private string newLine = "\u00B6"; // デフォルトはオリジナルどおり

/// <summary>
/// Gets/Sets the new line charactor.
/// </summary>
public string NewLine
{
  get { return newLine; }
  set
  {
    if (newLine != value)
    {
      newLine = value;
      OnPropertyChanged("NewLine");
    }
  }
}

改行文字を設定するコードは、VisualLineTextSource クラスの CreateTextRunForNewLine メソッドの中にあります。

TextRun CreateTextRunForNewLine()
{
  string newlineText = "";
  DocumentLine lastDocumentLine = VisualLine.LastDocumentLine;
  if (lastDocumentLine.DelimiterLength == 2)
  {
    // newlineText = "¶";  // この行をコメントアウト
    newlineText = this.TextView.Options.NewLine; // 追加
  }
  else if (lastDocumentLine.DelimiterLength == 1)
  {
    char newlineChar = Document.GetCharAt(lastDocumentLine.Offset + lastDocumentLine.Length);
    if (newlineChar == '\r')
      newlineText = "\\r";
    else if (newlineChar == '\n')
      newlineText = "\\n";
    else
      newlineText = "?";
  }

  return new FormattedTextRun(new FormattedTextElement(
    TextView.cachedElements.GetTextForNonPrintableCharacter(newlineText, this), 0),
      GlobalTextRunProperties);
}

以上です。TextEditorOptions クラスに新設した NewLine プロパティに希望の文字(string 型)を設定することができます。好みの問題ですが、下向き矢印の 0x2193 か、折り返し矢印の 0x21B5 のどちらかがいいと思います。


ハイライト表示

ハイライト表示とは、キーワードを色分けする機能です。私はコードエディタがほしいわけではないので、ハイライト表示に対するこだわりはそれほど大きくありません。最低限でいいと考えています。しかし、AvalonEdit は十分すぎるぐらいの機能がありますし、自分好みに編集することも可能です。また、独自の機能を組み込むことも可能です。

先に説明しましたが、私はハイライト表示に対する興味が小さいので、簡単に説明しておきます。ファイルの種類ごとのハイライト表示は .xshd ファイルを使って定義します。xshd は、XML 形式の "Syntax Highlighting Definition" の略だと思います。テキストファイルですから中身を見てもらえば編集可能だと理解できると思います。ちなみに、AvalonEdit に付属する .cs ファイル用の .xshd ファイルは以下のとおりです。

  AvalonEdit_Source\ICSharpCode.AvalonEdit\Highlighting\Resources\CSharp-Mode.xshd

TextEditor クラスの Load メソッドを使ってファイルを開くとファイルの拡張子に基づいて適切な .xshd ファイルを選択するようです。ちなみに、.cs とか .htm など 16 種類のファイル形式がサポートされています。


ハイパーリンクの文字色

AvalonEdit がサポートするハイパーリンクとしては、メールアドレスと URI とがありますが、その文字色は Brushes.Blue でハードコードされています。いえ、されていました。AvalonEdit 4.3 の TextView クラスに LinkTextBackgroundBrush と LinkTextForegroundBrush プロパティが追加され、変更可能になりました。


.xshd ファイルの作成

AvalonEdit はもともと、コードエディタとして作られたからでしょうか C# や HTML 構文などに対するハイライト表示の機能が組み込まれています。したがって、C# ファイルを読み込んだ場合はファイルの拡張子から判断して自動的に C# コード用のハイライト機能が有効になります。一方、組み込み済みでないファイル形式に対応するため、ユーザーが独自の .xshd ファイルを作成する機能も提供します。

AvalonEdit のソースファイルを格納したフォルダの下層にある Highlighting/Resources フォルダ内に組み込み済みの .xshd ファイルがあります。これはテキストファイルなので開いてみれば分かりますが、フォームを定義する XAML ファイルと基本的な構造はほぼ同じです。独自の .xshd ファイルを作る場合はこれらのファイルにならって直接編集するほうが便利だと思います。この項では、なぜそうかという理由を説明するために、あえて C# コードで .xshd ファイルを作成する手順を説明します。

まず、下図をみてください。これは AvalonEdit をテストするために作ったものです。内容はコードではなく、通常のテキストです。

AvalonEdit

テキストの一部の文字列がうすい青色になっていることが分かると思います。これは指定のキーワードと行の末尾に "@" が付く行に対してハイライト表示を適用しているからです。例として分かりやすいと思いますので、このハイライト表示をするための .xshd ファイルを作成します。

関連するクラスの多くは ICSharpCode.AvalonEdit.Highlighting.Xshd 名前空間内にありますが、例外が一つだけあります。HighlightingBrush クラスなのですが、このクラスのコンストラクタは protected なので直接インスタンスを作ることができません。また、文字列描画用のブラシを設定する手順もありません(と思う)。そこで、HighlightingBrush クラスから派生するクラスを作成することにしました。これを使うと、HighlightingBrush オブジェクトを Brush オブジェクトまたは Color 型で作成することができます。

public class XshdBrush : HighlightingBrush
{
  private SolidColorBrush FBrush;

  public XshdBrush(SolidColorBrush brush)
  {
    FBrush = brush;
    FBrush.Freeze();
  }

  public XshdBrush(Color color)	: this(new SolidColorBrush(color))
  {
  }

  public override Brush GetBrush(ICSharpCode.AvalonEdit.Rendering.ITextRunConstructionContext context)
  {
    return FBrush;
  }

  public override string ToString()
  {
    return FBrush.ToString();
  }
}

以上のクラスを作成したところで、.xshd ファイルを作成する C# コードを示しますが、まず、このコードの実行結果は次のとおりです。この .xshd ファイルを読み込むことで .txt ファイルのハイライト表示が有効になります。

<SyntaxDefinition name="TXT" extensions=".txt"
                  xmlns="http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008">
  <Color name="keywordColor" foreground="#FF00FFFF" />
  <RuleSet>
    <Keywords color="keywordColor">
      <Word>機  能</Word>
      <Word>構  文</Word>
      <Word>解  説</Word>
      <Word>宣  言</Word>
      <Word>使用例</Word>
    </Keywords>
    <Rule color="keywordColor">^.+@$</Rule>
  </RuleSet>
</SyntaxDefinition>

上のコードを出力する手順は以下のとおり。

private void button1_Click(object sender, RoutedEventArgs e)
{
  var color = new XshdColor();
  color.Name = "keywordColor";
  color.Foreground = new emanual.Wpf.TextEditor.XshdBrush(Brushes.Aqua); // 先に説明した XshdBrush クラス

  var colorReference = new XshdReference<XshdColor>(null, color.Name);

  var keywords = new XshdKeywords();
  keywords.Words.Add("機  能");
  keywords.Words.Add("構  文");
  keywords.Words.Add("解  説");
  keywords.Words.Add("宣  言");
  keywords.Words.Add("使用例");
  keywords.ColorReference = colorReference;

  var rule = new XshdRule();
  rule.ColorReference = colorReference;
  rule.Regex = "^.+@$";

  var ruleSet = new XshdRuleSet();
  ruleSet.Elements.Add(keywords);
  ruleSet.Elements.Add(rule);

  var def = new XshdSyntaxDefinition();
  def.Name = "TXT";
  def.Extensions.Add(".txt");

  def.Elements.Add(color);
  def.Elements.Add(ruleSet);

  var writer = new System.Xml.XmlTextWriter("output.xshd", System.Text.Encoding.UTF8);
  writer.Formatting = System.Xml.Formatting.Indented;

  var save = new SaveXshdVisitor(writer);
  save.WriteDefinition(def);

  writer.Close();
}

どうですか。見ただけでいやになるほどのヤヤコシさだと思いませんか。先にテキストとして直接編集するほうがよいと言った理由が理解できると思います。


.xshd ファイルの読み込み

次に、独自に作成した .xshd ファイルを読み込んで有効にする手順を説明します。ただし、.xshd ファイルを読み込む部分だけに焦点を合わせるため、実用的なアプリケーションでは当然必要なコードは省略します。

  using ICSharpCode.AvalonEdit.Highlighting.Xshd; // ← 名前空間

  var reader = new System.Xml.XmlTextReader("output.xshd");
  var definition = HighlightingLoader.Load(reader, HighlightingManager.Instance);

  textEditor.SyntaxHighlighting = definition;

  reader.Close();

種類の異なるファイルを読み込む場合、たとえば、C# コードを編集していて次に HTML 文を編集するときはファイルの拡張子から AvalonEdit は適切なハイライト表示を有効にします。しかし、C# コードから TXT ファイルに切り替える場合は、その都度、TXT ファイル用ハイライト表示を設定しなければならないことを付け加えておきます。


.xshd ファイルの編集

AvalonEdit に組み込み済みの XSHD は色の設定が決めうちですからユーザーの好みの色に設定できません。私はテキストエディタの背景色として Navy、文字色として White に設定していますから AvalonEdit の組み込み済み XSHD では不都合です。そこで、XSHD の色の設定をカスタマイズできるツールを考えてみました。アプリケーションの名前は XshdEditor です。

XshdEditor

このツールは、XSHD と同じ形式の XML ファイルを操作対象にします。ファイル内の Color 要素だけをピックアップし、表示します。Color 要素は以下にリストアップする属性で構成されています。

属性名属性値の例意味
nameComment などハイライト表示の対象部位
foregroundBlue など文字色
backgroundWheat など背景色
fontStylenormal, italic, obliqueフォントのスタイル
fontWeightnormal, boldフォントの線幅
exampleTextpublic override void ToString() などコード例

background はテキスト自体の背景色です。設定値はいずれも大文字と小文字の区別がありますので、注意してください。

さて、先に XshdEditor は Color 要素だけを操作対象にすると書きました。以下は、AvalonEdit に付属する CSharp-Mode.xshd の一部ですが、CommentMarkerSet の RuleSet の Keywords 要素の fontWeight と foreground 属性は操作対象にならないことを意味します。

<?xml version="1.0"?>
<SyntaxDefinition name="C#" extensions=".cs"
                  xmlns="http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008">
  <Color name="Comment" foreground="Green" exampleText="// comment" />
  <Color name="String" foreground="Blue" exampleText="string text = &quot;Hello, World!&quot;"/>
  <Color name="Char" foreground="Magenta" exampleText="char linefeed = '\n';"/>
  ....

  <RuleSet name="CommentMarkerSet">
    <Keywords fontWeight="bold" foreground="Red">
      <Word>TODO</Word>
      <Word>FIXME</Word>
    </Keywords>
    <Keywords fontWeight="bold" foreground="#E0E000">
      <Word>HACK</Word>
      <Word>UNDONE</Word>
    </Keywords>
  </RuleSet>

  ....

これらを操作対象にしたい場合は、属性を Color 要素のほうで設定しなければなりません。つまり、以下のように新しい Color 要素を追加します。このとき、できるだけ exampleText 属性を設定することをすすめます。そうすることで XshdEditor の [コード例] で設定状況を確認できるようになるからです。

  <Color name="Keyword1" foreground="Red" fontWeight="bold" exampleText="// TODO:" />
  <Color name="Keyword2" foreground="#E0E000" fontWeight="bold" exampleText="// HACK:" />

これにともなって、RuleSet のほうも変更します。

  <RuleSet name="CommentMarkerSet">
    <Keywords color="Keyword1">
      <Word>TODO</Word>
      <Word>FIXME</Word>
    </Keywords>
    <Keywords color="Keyword2">
      <Word>HACK</Word>
      <Word>UNDONE</Word>
    </Keywords>
  </RuleSet>

それともう一つ、XshdEditor は XSHD の "#E0E000" のような色の設定は受け入れますが、色の設定は XshdEditor が提供する 20 色パレット(下図を参照)の中から選択しなければなりません。色の好みは千差万別ですが、無限に必要だとは思いません。たとえば、DimGray はいいが、Gray は絶対にいやだという人はいないと思います。

XshdEditorPallete

なお、XshdEditor は「AvalonEdit クラスライブラリリファレンス」に含まれています。


その他

その他の機能としては、たくさんあるのですが、矩形選択が可能とだけ付け加えておきます。AvalonEdit を使い始めてまだ間がないので、理解が不十分だからです。ちなみに、テキストを選択するとき、通常は行単位ですが、矩形選択は矩形で囲んだ範囲を選択することをさします。

Note テキストを折り返すモードのとき、矩形選択はうまくいかないようです。AvalonEdit 4.3 では改善されたようですが、テストしていません。

大問題?

AvalonEdit をテストしてみればすぐに分かりますが、漢字変換用の窓(いわゆる、IME 窓)を開こうとすると、IME 窓はディスプレイの左上隅に表示されます。編集を終わって文字の変換を確定すると現在のキャレット位置にテキストは挿入されますので、機能としては問題ないのですが、目線を動かさなければならないのは決定的に問題です。

Note IME 窓はマウスを使ってドラッグできますので、目線に近い位置まで移動させることはできます。

要するに、AvalonEdit の開発者は IME がどんなものかを知らないのだと思います。欧米人ですから無理もありません。

この問題について、WEB サイトをあたったところ、多くの人がなんとかならないかと考えているようです。あるサイトでは WPF 自体が IME をサポートしないので、無理だろうとの書き込みがありました。この人物が権威ある立場の人なのかどうかは分かりませんが、だとすると、WPF の TextBoxコントロールはどうなんだと突っ込みたくなりますね。

ともあれ、現在、この問題の対策を考えているところです。もう少し、時間が必要です。


大問題が解決しました

前項の「大問題?」が解決しました。何とかいいアイデアはないかと WEB サイトをうろついていて見つけました。2012/05/06 付けの情報ですからできたてのホヤホヤです。タイトルは、"Add IME support to AvalonEdit" で、2 つのファイル(ImeNativeWrapper.cs と ImeSupport.cs)を追加し、Caret.cs に 3 行のコードを追加するだけです。関連する WEB サイトは以下のとおり。

Add IME support to AvalonEdit

ただし、このサイトは回りくどいですね。ウロウロさせられます。そこで、関連するファイルを以下の ZIP ファイルにまとめておきましたので、ご利用ください。

これらのファイルについては私に著作権はありませんが、オリジナル版の著作権は LPGL "Lesser General Public License" であることを付け加えておきます。

ImeSupport.zip (4,233 bytes)

なお、AvalonEdit 4.3 には上記のファイルの内容が追加されています(まったく同じ内容ではなく、一部変更されています)。


CodeCompletion と Snippet

私は AvalonEdit をテキストエディタとして使いたいので、CodeCompletion と Snippet とに興味があるとはいえません。CodeCompletion はともかくとして、Snippet のほうは短文の入力に使えそうです。そこで、両者の基本的な使い方を説明しておきたいと思います。

CodeCompletion

CodeCompletion とは何かについて、Visual Studio のコードエディタを例にして説明します。コードエディタ内でコードを編集するとき、クラス名に続いてピリオド "." を入力すると、次に入力すべきコードの候補リストを表示してくれます。このような機能を意味します。

AvalonEdit の CodeCompletion に関係するクラスは、9 つほどありますが、使うのは CompletionWindow クラスと ICompletionData インターフェースとの 2 つだけです。

ICompletionData インターフェースは、CompletionWindow オブジェクト内で表示するデータを定義するものです。データは CompletionWindow オブジェクトの CompletionList プロパティから参照する CompletionList オブジェクトに追加します。

さて、CodeCompletion を起動するキッカケはどうするかですが、TextArea クラスの TextEntered イベント内で入力したテキストに基づいて起動します。通常はピリオド "." が入力されたときになるでしょう。

以下は、AvalonEdit に付属するサンプルアプリケーションから引用しました。

// コンストラクタまたは Loaded イベント内でイベントハンドラを宣言
textEditor.TextArea.TextEntering += textEditor_TextArea_TextEntering;
textEditor.TextArea.TextEntered += textEditor_TextArea_TextEntered;

// メンバ変数として宣言
private CompletionWindow completionWindow;

private void textEditor_TextArea_TextEntered(object sender, TextCompositionEventArgs e)
{
  if (e.Text == ".") // ピリオドを入力したとき
  {
    // CodeCompletion 用ウインドウを開く
    completionWindow = new CompletionWindow(textEditor.TextArea);
    IList<ICompletionData> data = completionWindow.CompletionList.CompletionData;
    data.Add(new MyCompletionData("Item1"));
    data.Add(new MyCompletionData("Item2"));
    data.Add(new MyCompletionData("Item3"));
    completionWindow.Show();

    // ウインドウを閉じたときの処理
    completionWindow.Closed += delegate { completionWindow = null; };
  }
}

//---------------------------------------------------------------------------------------
private void textEditor_TextArea_TextEntering(object sender, TextCompositionEventArgs e)
{
  if (e.Text.Length > 0 && completionWindow != null)
  {
    if (!char.IsLetterOrDigit(e.Text[0]))
    {
      // CompletionWindow を開いているときに、英数字以外を入力しても文字を入力する
      completionWindow.CompletionList.RequestInsertion(e);
    }
  }

  // e.Handled = true; を設定してはならない
}

次は ICompletionData インターフェースを継承するクラスである。

// CodeCompletion 用リストボックスに設定するデータを定義するクラス
public class MyCompletionData : ICompletionData
{
  public System.Windows.Media.ImageSource Image { get { return null; }}
  public string Text { get; private set; }

  // 以下のプロパティはリスト項目としてテキスト以外を設定する場合に使うことになる
  public object Content { get { return this.Text; }}
  public object Description { get { return "Description for " + this.Text; } }

  public MyCompletionData(string text)
  {
    this.Text = text;
  }

  public void Complete(TextArea textArea, ISegment completionSegment, EventArgs insertionRequestEventArgs)
  {
    textArea.Document.Replace(completionSegment, this.Text);
  }
}

Snippet

"snippet" は、短文でいいと思います。Visual Studio の Snippet はキーワードを入力したあと、[Tab] を 2 回続けて入力すると、キーワードに対応した短文が入力されます。AvalonEdit では Snippet の起動のキッカケを何にするかは自由です。

まず、Snippet に関係するクラスをおさらいしておきましょう。実際のコードで使うクラスだけで、基本クラスは除きます。

クラス名機 能
Snippetコードスニペットの中心に位置するクラスで、Elements プロパティを構築したあと、Insert メソッドでスニペットを挿入する
SnippetBoundElementSnippetReplaceableTextElement 要素と関連付けるスニペット要素クラス
SnippetCaretElementスニペット挿入時にキャレット位置を調整するクラス
SnippetReplaceableTextElement編集可能なテキスト要素クラス
SnippetTextElementスニペットのテキスト要素をあらわすクラス

下図は、以下で説明するコードを使ってスニペットを挿入したところです。

Snippet

SnippetReplaceableTextElement オブジェクトの箇所の背景色がうすい緑色になっていますが、これは編集可能なテキストをあらわします。たとえば、"i" を "j" に変更すると、すべての "i" が "j" に変わります。また、編集を終了して [Return] すると、SnippetCaretElement オブジェクトの位置にキャレットを移動します。

private void ShowSnippetF5()
{
  var loopCounter = new SnippetReplaceableTextElement { Text = "i" };

  Snippet snippet = new Snippet
  {
    Elements =
    {
      new SnippetTextElement { Text = "for (int " },
      new SnippetBoundElement { TargetElement = loopCounter },
      new SnippetTextElement { Text = " = " },
      new SnippetReplaceableTextElement { Text = "0" },
      new SnippetTextElement { Text = "; " },
      loopCounter,
      new SnippetTextElement { Text = " < " },
      new SnippetReplaceableTextElement { Text = "end" },
      new SnippetTextElement { Text = "; " },
      new SnippetBoundElement { TargetElement = loopCounter },
      new SnippetTextElement { Text = "++)\n{\n" },
      new SnippetCaretElement(),
      new SnippetTextElement { Text = "\n}" }
    }
  };

  snippet.Insert(textEditor.TextArea);
}

さて、Snippet を起動するキッカケですが、Visual Studio のような方法は面倒くさそうです。そこで、上記のコードではファンクションキーの [F5] を押したときを想定しました。ファンクションキーの入力を拾うには、Window の PreviewKeyDown イベントあたりでいいでしょう。

いずれにしろ、かなり面倒ですね。テキストファイルで定義できる Visual Studio 方式のほうが使いやすいと思います。


AvalonEdit クラスライブラリリファレンス

AvalonEdit の入手先」で紹介したファイルの中に CHM 形式のヘルプファイルが含まれています。これを日本語化し、クラスライブラリリファレンスとして作成しました。ただし、私は AvalonEdit をコードエディタとしてではなく、テキストエディタとして使いたいので、コードエディタ特有の機能、たとえば、CodeCompletion とか Snippet への興味がありません。したがって、それらに関係するクラスについては収録しませんでした。

リファレンスには、AvalonEdit の基本的な知識、コントロールの設定に関する解説、コントロールを使うためのテクニックなどを補足として収録しました。また、解説文を読むだけでその機能を理解することは難しいですからテスト用のアプリケーションを作成しました。もちろん、このページで説明した AvalonEdit 改造計画を盛り込んでいます。

Note AvalonEdit はできるだけ最新版を使いたかったので、SharpDevelop 4.3.0.8877 に含まれているものを抜き出しました。これは IME 窓の問題の解決策を含んでいます。

また、「.xshd ファイルの編集」で紹介した XshdEditor も含みます。

なお、AvalonEdit の著作権にしたがって、すべてのソースコードを公開します。変更・追加した箇所にはコード中に "//<<" を付けておきましたので、プロジェクト全体を文字列検索すれば、どのように手を加えたかが分かるはずです。

公開先は次のとおり、Vector のサイトです。

http://www.vector.co.jp/soft/winnt/writing/se499007.html

−以上−