65.9K
CodeProject 正在变化。 阅读更多。
Home

创建高级记事本(Notepad)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (25投票s)

2016年4月16日

CPOL

6分钟阅读

viewsIcon

80107

downloadIcon

8276

在本文中,我们将创建一个记事本,它具有多标签文档、文档选择器、文件关联、打开/保存多个文件、行号、运行外部程序、在浏览器中查看文件、全屏模式等功能。

引言

我们都知道记事本是什么。但是现在,单文档编辑器很少使用。如果您想开发一个可以使用 C# 处理多个文档或文件的编辑器或 IDE,那么本文适合您。

您需要 Visual Studio Professional 2013 或更高版本以及 .NET Framework 4.5 或更高版本。

下载简单、自定义高级记事本的源代码和演示(.exe 文件)

在本文中,我们将创建一个可以单独处理多个文件或文档的记事本。
记事本中要开发的主要功能有新建、打开、保存、另存为、关闭、打印、运行等。

在本文中,我们将不涉及语法高亮,但如果您想为您的项目添加语法高亮,那么您可以使用已开发的编辑器,如 ICSharp code、Avalon Edit 或 EditorControl,或者您可以开发自己的编辑器。

在本文中,我们将只介绍如何处理打开、保存、关闭等主要功能。我们还将为我们的 RichTextBox 添加行号。请访问以下链接以了解如何为 RichTextBox 创建行号。

您还可以添加自动完成功能、自定义 Windows 窗体、自动完成括号、自定义控件。请访问以下链接以创建所有这些功能

如果您想创建自己的集成开发环境 (IDE),请参阅以下文章 

我们还将用 C# 创建深色自定义记事本,请参见上方或下方的黑色图片。

 

要自定义窗体,请参阅文章 使用面板在 C# 中创建自定义 Windows 窗体

代码相同,只需更改自定义代码和设计

下载简单和自定义记事本的源代码。

请记住,两者具有相同的项目名称。

使用面板在 C# 中创建自定义 Windows 窗体一文中,我们创建了另一个名为 CustomForm 的窗体,我们正在设计它,在主窗体中,我们只是更改其超类。在这里,我们只需要一个要自定义的窗体,即 MainForm。所以在这个项目中,我没有为自定义创建任何其他窗体。我按照我想要的方式自定义了主窗体,并在 MainForm.cs 文件中添加了代码。

Using the Code

我创建了一个包含行号的类 MyRichTextBox。对于创建多个选项卡式文档,当用户新建或打开文件时,您不能直接将 RichTextBox 添加到 TabControl

您必须创建一个类(我正在使用 MyTabPage),其超类为 TabPage ,它接受 MainForm 的对象,然后将此类添加到 TabControl

请记住对象的修饰符。

下载源代码以更好地理解。

这是 MyTabPage 类的代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
namespace AdvancedNotepad_CSharp
{
   public class MyTabPage : System.Windows.Forms.TabPage
    {
       public MainForm mainform;
       public MyRichTextBox _myRichTextBox = new MyRichTextBox();

       public MyTabPage(MainForm mf)
       {
           mainform = mf;

           this._myRichTextBox.Dock = DockStyle.Fill;
           this._myRichTextBox.richTextBox1.Text = "";
           _myRichTextBox.richTextBox1.Font = 
           new System.Drawing.Font("Monospaced", 11, FontStyle.Regular);
           this._myRichTextBox.richTextBox1.Select();

           _myRichTextBox.richTextBox1.TextChanged += 
           new EventHandler(this.richTextBox1_TextChanged);
           _myRichTextBox.richTextBox1.SelectionChanged += 
           new EventHandler(this.richTextBox1_SelectionChanged);

           _myRichTextBox.richTextBox1.LinkClicked += 
           new LinkClickedEventHandler(this.richTextBox1_LinkClicked);

           this.Controls.Add(_myRichTextBox);
       }
       
       private void richTextBox1_TextChanged(object sender, EventArgs e)
       {
           String str = this.Text;
           if (str.Contains("*"))
           {

           }
           else
           {
               this.Text = str + "*";
           }
       }

       private void richTextBox1_SelectionChanged(object sender, EventArgs e)
       {
           int sel = _myRichTextBox.richTextBox1.SelectionStart;
           int line = _myRichTextBox.richTextBox1.GetLineFromCharIndex(sel) + 1;
           int col = sel - _myRichTextBox.richTextBox1.GetFirstCharIndexFromLine(line - 1) + 1;

           mainform.LineToolStripLabel.Text = "Line : " + line.ToString();
           mainform.ColumnToolStripLabel.Text = "Col : " + col.ToString();
       }

       private void richTextBox1_LinkClicked(object sender, LinkClickedEventArgs e)
       {
           Process.Start(e.LinkText);
       }
    }
}

从 TabControl 中的当前选项卡获取 RichTextBox 控件

一旦您将选项卡添加到 TabControl,如果您想从选定的选项卡中获取添加的 RichTextBox 控件,请使用以下语法

var object=(object)TabControl.TabPages[tabcontrol selected index].Controls[0];

例如:

var _myRichTextBox = (MyRichTextBox)myTabControlZ.TabPages[myTabControlZ.SelectedIndex].Controls[0];

好的,让我们转到主窗体。

创建 Windows 窗体应用程序后,添加 MenuStripSplitContainer。将 TreeView (treeView1) 添加到 panel1,将 TabControl 添加到 splitcontainerpanel2。请记住,您不能直接将 ContextMenuStrip 添加到 RichTextBox,相反,您必须将 ContextMenuStrip 添加到 TabControl 中的每个添加的 RichTextBox。下载源代码以更好地理解。

现在让我们看一些重要的函数代码。

1) 打开

此函数将通过将 MultiSelect 属性设置为 true,从 OpenFileDialog 中选择文件来打开多个文件;让我们看看创建选项卡、一次读取一个文件并将该选项卡添加到 tabcontrol 的代码。另外,将 ContextMenuStrip 添加到 RichTextBox

        private void File_Open_MenuItem_Click(object sender, EventArgs e)
        {
            StreamReader strReader;
            String str;
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                String[] files = openFileDialog1.FileNames;
                foreach (string filename in files)
                {
                    MyTabPage tabpage = new MyTabPage(this);

                    strReader = new StreamReader(filename);
                    str = strReader.ReadToEnd();
                    strReader.Close();

                    String fname = filename.Substring(filename.LastIndexOf("\\") + 1);
                    tabpage.Text = fname;

                    //add contextmenustrip to richTextBox1
                    tabpage._myRichTextBox.richTextBox1.ContextMenuStrip = myContextMenuStrip;

                    tabpage._myRichTextBox.richTextBox1.Text = str;
                    myTabControlZ.TabPages.Add(tabpage);
                    myTabControlZ.SelectedTab = tabpage;

                    this.UpdateDocumentSelectorList();

                    /* check (*) is available on TabPage Text
                     adding filename to tab page by removing (*) */
                    fname = tabpage.Text;
                    if (fname.Contains("*"))
                    {
                        fname = fname.Remove(fname.Length - 1);
                    }
                    tabpage.Text = fname;

                    //adding filenames to OpenedFilesList list
                    OpenedFilesList.Add(filename);

                    FilenameToolStripLabel.Text = filename;
                    this.Text = "Advanced Notepad in C# [ "+fname+" ]";
                }

                if (myTabControlZ.SelectedIndex >= 0)
                {
                    var _myRichTextBox = 
                    (MyRichTextBox)myTabControlZ.TabPages[myTabControlZ.SelectedIndex].Controls[0];
                    _myRichTextBox.richTextBox1.Select();
                }
                UpdateWindowsList_WindowMenu();
            }
        }

2) 保存、另存为、全部保存

嗯,你知道如何保存文件。所以我们只看“全部保存”功能,一次性保存所有文件,而不会将一个文件的内容覆盖到另一个文件中。请看上面的图片。在状态栏中,您可以看到完整的文件名路径。这是逐个保存所有文件的代码。

        private void File_SaveAll_MenuItem_Click(object sender, EventArgs e)
        {
            if (myTabControlZ.TabCount > 0)
            {
                OpenedFilesList.Reverse();
                TabControl.TabPageCollection tabcoll = myTabControlZ.TabPages;

                foreach(TabPage tabpage in tabcoll)
                {
                    myTabControlZ.SelectedTab = tabpage;
                    myTabControlZ_SelectedIndexChanged(sender, e);
                    
                    if( ! tabpage.Text.Contains("Untitled"))
                    {
                        try
                        {
                            var _myRichTextBox = 
                            (MyRichTextBox)myTabControlZ.TabPages
				[myTabControlZ.SelectedIndex].Controls[0];
                            File.WriteAllText(FilenameToolStripLabel.Text, "");
                            StreamWriter strwriter = System.IO.File.AppendText
				(FilenameToolStripLabel.Text);
                            strwriter.Write(_myRichTextBox.richTextBox1.Text);
                            strwriter.Close();
                            strwriter.Dispose();
                        }
                        catch { }
                    }
                }

                System.Windows.Forms.TabControl.TabPageCollection tabcollection = 
								myTabControlZ.TabPages;
                foreach (TabPage tabpage in tabcollection)
                {
                    String str = tabpage.Text;
                    if (str.Contains("*")&& !str.Contains("Untitled"))
                    {
                        str = str.Remove(str.Length - 1);
                    }
                    tabpage.Text = str;
                }
                UpdateWindowsList_WindowMenu();
            }
        } 

3) 关闭

如果您使用过像 Notepad++ 这样的编辑器,它提供了关闭文件的功能。在这里,我们也将创建该功能。此功能不过是在保存文件后从 TabControl 中删除选项卡并从 treeView1 中删除节点。这是关闭文档的代码。下载源代码以查看“全部关闭”功能的代码。

        private void File_Close_MenuItem_Click(object sender, EventArgs e)
        {
            if (myTabControlZ.TabCount > 0)
            {
                TabPage tabpage = myTabControlZ.SelectedTab;
                if (tabpage.Text.Contains("*"))
                {
                    DialogResult dg = MessageBox.Show("Do you want to save " + 
                    tabpage.Text + " file before close ?", 
                    "Save before Close ?", MessageBoxButtons.YesNo);
                    if (dg == DialogResult.Yes)
                    {
                        //save file before close
                        File_Save_MenuItem_Click(sender, e);
                        //remove tab
                        myTabControlZ.TabPages.Remove(tabpage);

                        //RemoveFileNamesFromTreeView(tabpage.Text);
                        this.UpdateDocumentSelectorList();

                        UpdateWindowsList_WindowMenu();
                        myTabControlZ_SelectedIndexChanged(sender, e);

                        LineToolStripLabel.Text = "Line";
                        ColumnToolStripLabel.Text = "Col";

                        if (myTabControlZ.TabCount == 0)
                        {
                            FilenameToolStripLabel.Text = "Advanced Notepad in C#";
                        }
                    }
                    else
                    {
                        //remove tab
                        myTabControlZ.TabPages.Remove(tabpage);

                        UpdateDocumentSelectorList();

                        UpdateWindowsList_WindowMenu();
                        myTabControlZ_SelectedIndexChanged(sender, e);

                        LineToolStripLabel.Text = "Line";
                        ColumnToolStripLabel.Text = "Col";

                        if (myTabControlZ.TabCount == 0)
                        {
                            FilenameToolStripLabel.Text = "Advanced Notepad in C#";
                        }
                    }
                }
                else
                {
                    //remove tab
                    myTabControlZ.TabPages.Remove(tabpage);

                    RemoveFileNamesFromTreeView(tabpage.Text);
                    UpdateDocumentSelectorList();

                    UpdateWindowsList_WindowMenu();
                    myTabControlZ_SelectedIndexChanged(sender, e);

                    LineToolStripLabel.Text = "Line";
                    ColumnToolStripLabel.Text = "Col";

                    if (myTabControlZ.TabCount == 0)
                    {
                        FilenameToolStripLabel.Text = "Advanced Notepad in C#";
                    }
                }

                if (myTabControlZ.SelectedIndex >= 0)
                {
                    var _myRichTextBox = 
                    (MyRichTextBox)myTabControlZ.TabPages[myTabControlZ.SelectedIndex].Controls[0];
                    _myRichTextBox.richTextBox1.Select();
                }
            }
            else
            {
                FilenameToolStripLabel.Text = "Advanced Notepad in C#";

                LineToolStripLabel.Text = "Line";
                ColumnToolStripLabel.Text = "Col";
            }
        }

TabControl 上下文菜单

请看上图,它为选定的 tabpage 提供了保存、关闭、关闭除此以外的所有、打开文件文件夹等功能。您可以在几乎所有高级编辑器(如 Notepad++)或 IDE(如 Visual Studio)中看到此功能。
您只需要创建上下文菜单条,向其中添加菜单,然后将此菜单条添加到选项卡控件中。

1) 关闭除此以外的所有

此函数执行的操作是删除所有其他选项卡,而不删除选定或当前选项卡。这是代码

        private void myTabControl_CloseAllButThis_MenuItem_Click(object sender, EventArgs e)
        {
            String tabtext = myTabControlZ.SelectedTab.Text;
            if (myTabControlZ.TabCount > 1)
            {
                TabControl.TabPageCollection tabcoll = myTabControlZ.TabPages;
                foreach (TabPage tabpage in tabcoll)
                {
                    myTabControlZ.SelectedTab = tabpage;
                    if (myTabControlZ.SelectedTab.Text != tabtext)
                    {
                        File_Close_MenuItem_Click(sender, e);
                    }
                }
            }
            else if (myTabControlZ.TabCount == 1)
            {
                File_Close_MenuItem_Click(sender, e);
            }
        }

2) 打开文件文件夹

此函数打开文件保存的文件夹。这是代码

        private void myTabControl_OpenFileFolder_MenuItem_Click(object sender, EventArgs e)
        {
            if(myTabControlZ.TabCount>0)
            {
                if( ! myTabControlZ.SelectedTab.Text.Contains("Untitled"))
                {
                    if(FilenameToolStripLabel.Text.Contains("\\"))
                    {
                        TabPage tabpage = myTabControlZ.SelectedTab;
                        String tabtext = tabpage.Text;
                        if(tabtext.Contains("*"))
                        {
                            tabtext = tabtext.Remove(tabtext.Length - 1);
                        }
                        String fname = FilenameToolStripLabel.Text;
                        String filename=fname.Remove(fname.Length-(tabtext.Length+1));
                        Process.Start(filename);
                    }
                }
            }
        }

文件关联

Visual Studio 允许您为应用程序添加特定的文件扩展名。要访问此属性,.NET Framework 版本必须大于或等于 3.5。要添加文件扩展名,请转到您的项目属性。
选择发布选项卡。单击选项按钮。一旦出现“发布选项”对话框,然后选择“文件关联”项,并在此处添加您的文件扩展名和图标。

那么如何在双击文件时在应用程序中打开文件呢?

嗯,这很简单。当您双击文件或右键单击文件并选择程序时,该文件名将作为参数传递给应用程序。

所以您只需在程序的主函数中打开该文件。首先,在 MainForm 中定义一个打开文件并接受文件名作为参数的函数。您必须将此函数修饰符定义为 public

在这里,定义一个函数,其代码与“打开文件”代码相同,但不使用 OpenFileDialog,而是使用数组的 string 作为函数的参数。我使用了 OpenAssociatedFiles_WhenApplicationStarts(String[] files) 函数。

您必须在程序的主函数中调用此函数,该函数位于 Programs.cs 文件中。
首先,检查参数是否为 null,如果为 null,则调用 Application.Run(new MainForm()); 否则创建 MainForm 对象并调用已定义的函数以打开这些文件 (OpenAssociatedFiles_WhenApplicationStarts(args);)。

这是我的应用程序或 Program.cs 文件的主代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.IO;
namespace AdvancedNotepad_CSharp
{
    static class Program
    {
        [STAThread]
        static void Main(String[] args)
        {
            if (args != null && args.Length > 0)
            {
                String[] files = args;

                MainForm mf = new MainForm();
                mf.IsArgumentNull = false;
                mf.OpenAssociatedFiles_WhenApplicationStarts(files);
                Application.EnableVisualStyles();
                Application.Run(mf);
            }
            else
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new MainForm());
            }
        }
    }
}

鼠标点击树节点时选择选项卡

如您所知,每个编辑器都有一个文档选择器,用户可以在其中单击文档列表并激活该文档。

在选项卡式文档中,当您双击树节点时,会在选项卡控件中搜索与树节点相同的文本,如果文本匹配,则选择该选项卡。

这是选择选项卡的代码。

        private void treeView1_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            String str = treeView1.SelectedNode.ToString();
            String st = str.Substring(str.LastIndexOf(":") + 2);
            int treenode_length = st.Length;
            int tab_count = myTabControlZ.TabCount;

            System.Windows.Forms.TabControl.TabPageCollection tb = myTabControlZ.TabPages;
            foreach (TabPage tabpage in tb)
            {
                String tabstr = tabpage.Text;
                int tab_length = tabstr.Length;
                if (tabstr.Contains(st))
                {
                    myTabControlZ.SelectedTab = tabpage;
                }
            }

            if (myTabControlZ.SelectedIndex >= 0)
            {
                var _myRichTextBox = 
                (MyRichTextBox)myTabControlZ.TabPages[myTabControlZ.SelectedIndex].Controls[0];
                _myRichTextBox.richTextBox1.Select();
            }

            this.UpdateWindowsList_WindowMenu();
        } 

下载源代码以更好地理解并查看所有功能。

在这里,我只使用了简单的 RichTextBox,只是展示了所有功能的操作,如打开、全部保存、关闭等,但您可以使用任何语法高亮文本编辑器。

© . All rights reserved.