Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#6.0

Creating Advanced Notepad in C#

4.91/5 (25 votes)
31 Jan 2017CPOL6 min read 78.9K   8.2K  
In this article, we will create a Notepad with features like Multi Tabbed Documents, Document Selector, File Association,Opening/Saving Multiple Files, Line Numbers, Running External Programs, Viewing files in Browser, Full Screen Mode, etc.

Image 1

Image 2

Image 3

Introduction

Well, we all know what Notepad is. But nowadays, a single document editor is rarely used. Consider you want to develop an editor or IDE that can handle multiple documents or files using C#, so this article is for you.

You require Visual Studio Professional 2013 or higher version and .NET framework 4.5 or higher.

Download the source code for Simple,Custom advanced notepad & also demo(.exe files)

In this article, we will create a Notepad that can handle multiple files or documents separately.
The kind of main functions that are there to develop in a Notepad are New, Open, Save, Save As, Close, Print, Run, etc.

In this article, we will not see Syntax Highlighting, but if you want to add syntax highlighting to your project, then you can use developed editors like ICSharp code, Avalon Edit or EditorControl, or you can develop your own editor.

In this article, we will see only how to handle main functions like Open, Save, Close, etc. We will also add Line Numbers to our RichTextBox. Go to the following link to see how to create line numbers for RichTextBox.

You can also add Auto Completion function, Custom Windows Form, Auto Complete Brackets, Custom Controls. Go to the following links to create all these functions:

If you want to create your own Integrated Development Environment(IDE) then see following article 

We will also create dark custom notepad in C#,see above or following black image.

Image 4 

To customize a form see article Creating Custom Windows Forms in C# using Panels

The code is same only just change in customization code & in design

Download the source code for both simple & customize notepads.

Remeber both have same project names.

In Creating Custom Windows Forms In C# using Panels article, we created another form named CustomForm which we are designing & in mainform we just changing its super class. Here we need only one form to be customize which is a MainForm. so in this i didnt created any another form for customize.i have customized the main form in the way what i wanted & also adding codes in MainForm.cs file.

Using the Code

I have created a class with line numbers MyRichTextBox. For creating multiple tabbed documents, you cannot directly add RichTextBox to TabControl when user creates a New or Open a file.

You have to create a class (I am using MyTabPage) with its super class TabPage that takes a object of MainForm and then add this class to TabControl.

Remember about Modifiers of objects.

Download the source code for better understanding.

Here's the code of MyTabPage class.

C#
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);
       }
    }
}

Getting RichTextBox Control from Current Tab in TabControl

Once you added a Tab to TabControl and if you want to get the added RichTextBox control from the selected tab, then use the following syntax:

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

e.g.:

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

All right, let's move to the main form.

Once you created the Windows Forms Application, then add MenuStrip, SplitContainer. Add TreeView (treeView1) to panel1 and TabControl to panel2 of splitcontainer respectively. Remember you directly cannot add ContextMenuStrip to RichTextBox, rather than that, you must add ContextMenuStrip to every added RichTextBox to a TabControl. Download the source code for better understanding.

Now let's see some important functions code.

1) Open

This function will open multiple files from selecting files from OpenFileDialog by setting MultiSelect property to true; Let's see the code that creates tab, read each file at a time and add that tab to tabcontrol. Also, add ContextMenuStrip to RichTextBox.

C#
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) Save, Save As, Save All

Well, you know how to save a file. So we will see only Save All function for saving all files at once without overwriting one file contents to another file contents. See the above image. In status strip, you can see full filename path. Here's the code to save all files one by one.

C#
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) Close

If you have used any editor like Notepad++, it provides a function to close a file. Here, we will also create that function. This function is nothing but to remove tab from TabControl and remove node from treeView1 after saving a file. Here's the code to close a document. Download the source code to view Close All function code.

C#
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 ContextMenuStrip

Image 5

See the above image that provides functions to selected tabpage like Save, Close, Close All But This, Open File Folder, etc. You can see this function in almost all advanced editors like Notepad++ or IDEs like Visual Studio.
You just need to create context menu strip, adding menus to it and adding this menu strip to tabcontrol.

1) Close All But This

This function performs action like to remove all other tabs without removing selected or current tab. Here's the code:

C#
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) Open File Folder

This function opens the folder where the file is saved. Here's the code:

C#
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);
            }
        }
    }
}

File Association

Visual Studio allows you to add specific file extension to the application. To access this property, the .NET Framework version must be greater than or equal to 3.5. For adding file extension, go to your Project Properties.
Select Publish tab. Click on Options button. Once "Publish Options" Dialog box appeared, then select "File Associations" item and add your file extension with icon here.

Image 6

So how to open a file in the application when double clicking on file?

Well, it's so simple. When you double click on a file or right click on a file & select a program, that file name is passed as an argument to the application.

So you just have to open this file in the application in the main function of the program. First, define the function in the MainForm that opens a file and takes a filename as an argument. You must define this function modifier to public.

Here, define a function with code is same as Open file code without using OpenFileDialog, instead that use string of array as argument to function. I used OpenAssociatedFiles_WhenApplicationStarts(String[] files) function.

You have to call this function in the main function of program which is in Programs.cs file.
First, check that the arguments are not null, if it is null, then call Application.Run(new MainForm()); otherwise create object of MainForm and call the defined function that open these files(OpenAssociatedFiles_WhenApplicationStarts(args);).

Here's the main code of my application or Program.cs file code:

C#
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());
            }
        }
    }
}

Select Tab when Mouse Click on Tree Node

As you know, every editor has a document selector where a user can click on list of document and that document is activated.

In Tabbed document,when you double click on tree node, then the same text of tree node is searched in tabcontrol, if that text is matched, then that tab is selected.

Here's the code to select the tab.

C#
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();
}

Download the source code for better understanding and to view all functions.

Here, I just used only simple RichTextBox, just showing about actions all the functions like Open, Save All, Close, etc., but you can use any Syntax Highlighting text editor.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)