できること
- 行番号付きのリッチテキストボックスを実現
- ユーザは行番号部分を編集できない、
- テキスト部分のみ編集可能
サンプルコード
RichTextBoxを継承したクラスを作成してビルド。成功するとツールボックスにRichTextBoxLNが表示されるので、フォームに配置して使用します。namespaceは自身の環境に合わせて変更してください。
バグ等含まれている可能性ありますので、ご自身でデバッグをお願いします。
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices; // DllImport
namespace RichTextBoxWithLineNumber
{
class RichTextBoxLN : RichTextBox
{
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
const int WM_PAINT = 15;
const int EM_SETMARGINS = 0xD3;
// 左端マージン
public int LeftMargin = 50;
public new string Text
{
// そのまま取得
get { return base.Text; }
// マージン設定してテキストをセット
set { SetLeftMargin(); base.Text = value; }
}
protected override void WndProc(ref System.Windows.Forms.Message m)
{
if (m.Msg == WM_PAINT)
{
Invalidate();
base.WndProc(ref m);
using (Graphics g = base.CreateGraphics())
{
DrawLineNo(g);
}
}
else
{
base.WndProc(ref m);
}
}
private void SetLeftMargin()
{
SendMessage(this.Handle, EM_SETMARGINS, (IntPtr)1, (IntPtr)LeftMargin);
}
protected void DrawLineNo(Graphics g)
{
// 指定位置に最も近い文字のインデックスを取得
int charIndex = this.GetCharIndexFromPosition(new Point(LeftMargin, 0));
// コントロールのテキスト内の指定した文字位置から行番号(0から始まる)を取得
int lineIndex = this.GetLineFromCharIndex(charIndex);
for (; lineIndex < this.Lines.Length; lineIndex++)
{
// 指定された行の先頭文字のインデックスを取得
charIndex = this.GetFirstCharIndexFromLine(lineIndex);
if (charIndex < 0) break;
// 指定の文字インデックスにおけるコントロール内の位置を取得
Point point = this.GetPositionFromCharIndex(charIndex);
if (point.Y > this.ClientRectangle.Height) break;
// 行番号を描画
string strLineNo = (lineIndex + 1).ToString();
g.DrawString(strLineNo, this.Font, Brushes.Black, new PointF(0, point.Y));
}
}
}
}
■参考(背景描画の仕方について下記を参考にしました)
https://stackoverflow.com/questions/16989957/drawing-over-richtextbox