Разработка простого синтаксического анализатора, страница 4

Последние два параметра (true, true) указывают на то, что все теги из keywords должны быть цветными и попадать в список слов с функцией авто-завершения. Ясно, что конструкторов в структурах Keyword, Comment (или классах ColorWord, AutoWord и т. д.) должно быть много, столько — сколько надо для удобной работы с ними. Думайте, дерзайте — ваш компонент SyntaxBox должен быть легко управляемым (для клиента).

Разработка компонента

При разработке компонента (класса SyntaxBox, производного от RichTextBox) вам надо создать множество полей его данных. Предлагаю поместить их объявления в отдельный блок, например:

#region Data Fields

private bool       // Поля данных, представленные свойствами

isCaseSensitive,  // Комментируйте, не жалея сил

isFiltered;       // Комментируйте, не жалея сил

private Highlighter highlighter;    // Объект вспомогательного класса

private int        // Поля данных для внутреннего использования

pos,              // Текущая позиция в тексте документа RTF

start,            // Начальная позиция выделенного блока текста

end;              // Конечная позиция выделенного блока текста

. . .

private Dictionary<Color, int> colorTable;   // Таблица цветов

private StringBuilder rtf;    // Черновой вариант текста разметки

. . .

private Stack<UndoInfo> undo, redo;

private bool isUndoing;

. . .

#endregion

В другой блок поместите виртуальные методы, переопределенные в вашем классе, например:

#region Overriden methods

protected override void InitLayout ()

{

isCaseSensitive = isParsing = ignoreLostFocus = isUndoing = false;

isFiltered = true;

. . .

promptList = new ListBox ();

undo = new Stack<UndoInfo> (128);   // Это не размер, а Capacity

. . .

base.InitLayout ();    // Вызов родительской версии

Controls.Add (promptList);

}

Не жалейте усилий, затрачиваемых на создание IntelliSense-комментариев. Они сильно помогают в процессе разработки — высвечивают введенный вами текст в окнах автозаполнения и окнах типа ToolTip, напоминая вам суть данного метода, и подсказывая верное решение.

/// <summary>

/// Анализ текста, установка цвета, включение окна со списком ключевых слов

/// </summary>

protected override void OnTextChanged (EventArgs e)

{

if (isParsing || TextLength == 0)

return;

isParsing = true;

LockWindowUpdate (Handle);  // API: Тормозит перерисовку элемента управления

. . .

base.OnTextChanged (e);      // Вызов родительской версии

. . .

Parse ();

. . .

LockWindowUpdate (IntPtr.Zero); // Теперь можно рисовать

Invalidate ();

isParsing = false;

if (promptList.Visible && isFiltered)

CompleteWord ();

}

Мне понадобились некоторые объекты Win32 API. Думаю, что вам также не удастся обойтись без них.

#region Win32 API

public const int

WM_PAINT = 0xF,

WM_KEYDOWN = 0x100,

. . .

EM_GETSCROLLPOS = WM_USER + 221,

EM_SETSCROLLPOS = WM_USER + 222,

. . .

VK_RETURN = 13,

VK_CONTROL = 17,

. . .

VK_DOWN = 40;

[StructLayout (LayoutKind.Sequential)]

public struct POINT { public int x, y; }

. . .

[DllImport ("user32")]

public static extern int SendMessage (IntPtr hwnd, int wMsg, int wParam, IntPtr lParam);

[DllImport ("user32")]

public static extern short GetKeyState (int nVirtKey);

. . .

[DllImport ("user32")]

public unsafe static extern int SetScrollInfo (IntPtr hwnd, int fnBar,

SCROLLINFO* lpsi, bool fRedraw);

#endregion

В любом классе, связанном с обработкой интерфейсных событий, вы можете переопределить виртуальный метод WndProc. Это — аналог оконной процедуры для элемента RichTextBox в мире Win32. Он действует в мире .NET и обслуживает класс (точнее, компонент) SyntaxBox. С помощью этого метода можно более гибко реагировать на события, порождаемые мышью и клавиатурой. Когда я впервые узнал, что в .NET можно переопределить оконную процедуру, на меня это произвело сильное впечатление.

protected override void WndProc (ref Message m)

{

switch (m.Msg)

{

case WM_PAINT: // Не рисуем, пока идет синтаксический разбор