Сложный древовидный дизайн C#

Я пытаюсь разработать IDE-подобную (нередактируемую) программу с элементом управления RichTextBox. По сути, мне нужно древовидное представление, которое расположено слева от RTB, чтобы расширять/сворачивать определенную часть моего кода всякий раз, когда пользователь нажимает кнопки +/-. Расширяемые складные диапазоны определяются везде, где видны фигурные скобки. Например, в RTB, если бы у меня было что-то вроде:

int main()
{
   if (...)
   {
       if (...)
       {
       }
   }
   else
   {
   }
}

Если бы я щелкнул самую верхнюю фигурную скобку, это разрушило бы все внутри основной функции. В основном то, что содержится внутри этой фигурной скобки, и есть то, что свернуто. Таким образом, я пытаюсь разработать что-то очень похожее на функцию кода расширения/свертывания Visual Studio, за исключением того, что она также делает то же самое с функциями if/else.

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

Проблема, с которой я сталкиваюсь, в основном заключается в том, как приступить к проектированию фактического древовидного представления. Мне нужно, чтобы древовидное представление было линейным, чтобы узлы не добавлялись поверх других. Я не знаю ни одного подхода, который может добавить кнопку развертывания/свертывания без фактического добавления дочерних узлов поверх другого узла.

Кроме того, за исключением кнопок +/- и единственной вертикальной линии, мне нужно, чтобы узлы древовидной структуры были нередактируемыми, невидимыми и неактивными.

Наконец, и это при условии, что если я выполнил вышеуказанные требования, мне нужно, чтобы событие вертикальной прокрутки RTB также правильно прокручивало древовидную структуру. То есть раздел свертывания/развертывания Treeview будет обновляться в зависимости от части кода, видимой в RTB.

Вот фрагмент кода, который я использую для инициализации дерева:

public partial class LogicSimulationViewerForm : Form
{
    private List<Tuple<string,Boolean>> visibleLines = new List<Tuple<string,Boolean>>();
    private List<Tuple<int, int>> collapseRange = new List<Tuple<int, int>>();

    private void TreeInit()
    {
        TreeNode tn;
        Stack<int> openBracketLine = new Stack<int>();
        int i = 0;
        TreeLogicCode.Nodes.Clear();
        foreach (string s in rtbLogicCode.Lines)
        {
            visibleLines.Add(Tuple.Create(s, true));
            if (s == "{")
            {
                openBracketLine.Push(i);
            }
            else if (s == "}")
            {
                collapseRange.Add(Tuple.Create(openBracketLine.Pop(),i));
            }
            i++;
        }
    }

Вот исходный код Designer.sc, хотя я думаю, что это не обязательно, но на всякий случай:

namespace DDCUI
{
    partial class LogicSimulationViewerForm
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.TreeLogicCode = new System.Windows.Forms.TreeView();
            this.labelLogicCode = new System.Windows.Forms.Label();
            this.rtbLogicCode = new System.Windows.Forms.RichTextBox();
            this.SuspendLayout();
            // 
            // TreeLogicCode
            // 
            this.TreeLogicCode.Dock = System.Windows.Forms.DockStyle.Left;
            this.TreeLogicCode.Location = new System.Drawing.Point(50, 0);
            this.TreeLogicCode.Name = "TreeLogicCode";
            this.TreeLogicCode.Scrollable = false;
            this.TreeLogicCode.Size = new System.Drawing.Size(40, 600);
            this.TreeLogicCode.TabIndex = 4;
            // 
            // labelLogicCode
            // 
            this.labelLogicCode.BackColor = System.Drawing.Color.LightGray;
            this.labelLogicCode.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.labelLogicCode.Dock = System.Windows.Forms.DockStyle.Left;
            this.labelLogicCode.ForeColor = System.Drawing.SystemColors.ControlText;
            this.labelLogicCode.Location = new System.Drawing.Point(0, 0);
            this.labelLogicCode.Margin = new System.Windows.Forms.Padding(3);
            this.labelLogicCode.Name = "labelLogicCode";
            this.labelLogicCode.Padding = new System.Windows.Forms.Padding(3);
            this.labelLogicCode.Size = new System.Drawing.Size(50, 600);
            this.labelLogicCode.TabIndex = 3;
            this.labelLogicCode.TextAlign = System.Drawing.ContentAlignment.TopRight;
            // 
            // rtbLogicCode
            // 
            this.rtbLogicCode.Dock = System.Windows.Forms.DockStyle.Fill;
            this.rtbLogicCode.Location = new System.Drawing.Point(90, 0);
            this.rtbLogicCode.Name = "rtbLogicCode";
            this.rtbLogicCode.Size = new System.Drawing.Size(510, 600);
            this.rtbLogicCode.TabIndex = 5;
            this.rtbLogicCode.Text = "";
            this.rtbLogicCode.VScroll += new System.EventHandler(this.rtbLogicCode_VScroll);
            // 
            // LogicSimulationViewerForm
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(600, 600);
            this.Controls.Add(this.rtbLogicCode);
            this.Controls.Add(this.TreeLogicCode);
            this.Controls.Add(this.labelLogicCode);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
            this.Name = "LogicSimulationViewerForm";
            this.Text = "LogicSimulationViewerForm";
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.TreeView TreeLogicCode;
        private System.Windows.Forms.Label labelLogicCode;
        private System.Windows.Forms.RichTextBox rtbLogicCode;
    }
}

Я бы очень ценю любые рекомендации по решению этого вопроса. Заранее спасибо.

6
задан l46kok 20 June 2012 в 02:48
поделиться