Click here to Skip to main content
15,883,908 members
Articles / Programming Languages / C#
Article

Advanced Text Editor with Ruler

Rate me:
Please Sign up or sign in to vote.
4.85/5 (47 votes)
20 Mar 2008CPOL3 min read 430.1K   32.4K   164   134
Extending RichTextBox with ruler and much more
AdvTextEdit.PNG

Introduction

About two years ago I was creating a project for university. It was a complex of five programs that were related to testing (checking knowledge I mean). One of them contained a text editor. But unfortunately, I didn't know how to do that, that's why it was very simple. So, after these two years, I decided to rewrite my program in C# .NET (initially, it was written in VB.NET) and create a new powerful text editor. You can see part of it here.

Background

I spent a lot of time(!) searching the Internet for controls like this, but the best ones are shareware and others did not fit my needs. So, what does this control have? I tried to make it look like Microsoft Word and I think that there are some similarities. The ruler lets you change the following: left and right margins, left indent, hanging indent and right indent. You also can disable margins (their values are set to 1). You can see how it looks in the picture above.

Also, you can add tabs by clicking on the control with the left mouse button. But it is allowed only inside the area bounded by margins. If you want to remove a tab, just drag it off from the control.

The editor lets you use lists, underline styles, advanced char styles (you can create your own links, that are not words starting with "http://" or even "www"), OLE functionality is also available. I want to thank Oscar Londoño for his article Inserting Images into a RichTextBox Control (The OLE Way). It helped me a lot to deal with OLE. This project contains his code.

Using the Code

You can use the code according to the CPOL.

Projects are created as Windows Applications, but you can easily convert them into *.dll or just embed code into your project.

Unfortunately, I removed Visual Studio 2005, so, sorry but I can't create and upload a Visual Studio 2005 project. But you can import all required files into a Visual Studio 2005 project without any problems. However, note that Visual Studio 2008 added some new namespaces (like LINQ) that Visual Studio 2005 does not "understand". Just remove them. That's all. You are ready.

Points of Interest

One thing that shocked me is that Microsoft has released RichTextBox 6.0! (It is distributed with Microsoft Office 2007) but... with one exception. There is no documentation about its features. All that I've found is a list of added functions. You can find it here. There are also descriptions for all released versions of RichTextBox.

History

  • 7 January 2008: Initial release
  • 16 January 2008: Projects for Visual Studio 2005 and 2008 posted instead of standalone control.
  • 26 January 2008: Posted completed AdvancedTextEditor project. It is available for Visual Studio 2005 and Visual Studio 2008.
  • 10 February 2008: Fixed PrintDialog bug. It didn't receive focus when shown. Now it's OK. Thanks to Chris Schucker for bug report and recommendations.
  • 22 February 2008: Added new functionality (full text justification, underline styles and colors and other)
  • 24 February 2008: Fixed bug with conversion from millimeter to pixel and vice versa Thanks to Chris Schucker. Also corrected bug which caused incorrect display of the indents.
  • 19 March 2008: Version 2.0 released. A lot of changes including lists, OLE, underline styles, etc.

Additions

I understand that I am not able to include everything into the control, that's why you can freely add something useful or change code to fit your needs. But, please inform me about that, just email me at krasssss@mail.ru. It's just to let anyone use an upgraded (and corrected) version of that control. Of course, advisors will be mentioned.

License

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


Written By
Kazakstan Kazakstan
Currently I am studying at East Kazakhstan State Technical University. My future occupation is engineer-programmer.

I use Visual Basic, C#, Delphi and a little C++. Also I am interested in using SQL and Perl.

Comments and Discussions

 
AnswerRe: A minor bug in your control any idea how to fix Pin
Aleksei Karimov27-Mar-09 4:07
Aleksei Karimov27-Mar-09 4:07 
GeneralRe: A minor bug in your control any idea how to fix Pin
Brian Cohen1-Apr-09 1:38
Brian Cohen1-Apr-09 1:38 
GeneralRe: A minor bug in your control any idea how to fix Pin
frankelman4-Jun-09 21:18
frankelman4-Jun-09 21:18 
GeneralRe: A minor bug in your control any idea how to fix Pin
Brisingr Aerowing4-Jun-12 4:35
professionalBrisingr Aerowing4-Jun-12 4:35 
AnswerRe: A minor bug in your control any idea how to fix Pin
Michał Orlik16-Jun-09 6:12
Michał Orlik16-Jun-09 6:12 
GeneralRe: A minor bug in your control any idea how to fix Pin
Brian Cohen16-Jun-09 8:38
Brian Cohen16-Jun-09 8:38 
QuestionHyperlinks in Advanced Text Editor Pin
frankelman4-Jan-09 1:32
frankelman4-Jan-09 1:32 
AnswerRe: Hyperlinks in Advanced Text Editor Pin
Aleksei Karimov4-Jan-09 23:21
Aleksei Karimov4-Jan-09 23:21 
Hello.
Actually, this is an issue of the RichTextBox. Well, I found a solution.
Firstly, it's easier to use arbitrary links (like, click here, instead of file://somefile).

You sould add a function to the ExtendedRichTextBox, which will instert hyperlinks. Here is what I use:

internal void InsertHyperlink(string text, string address, Color linkColor)
{
    if (address == null) return; if (address == "") return;
    if (text == "") text = address;

    string _val = "", _val2 = "";
    string s = @"{\rtf1\ansi\ansicpg1251\deff0\deflang1049" +  //{\fonttbl{\f0\fnil\fcharset1200 Times New Roman;}}" +
               Environment.NewLine + @"{\colortbl ;\red" + linkColor.R.ToString() + @"\green" + linkColor.G.ToString() + @"\blue" + linkColor.B.ToString() + ";}" +
               Environment.NewLine + @"{\*\generator Msftedit 5.41.15.1507;}\viewkind4\uc1 ";
    string s1 = "\\pard  \\protect {\\field{\\*\\fldinst{HYPERLINK \"";
    string s2 = "\" }}{\\fldrslt{\\cf1\\ul ";
    string s3 = "}}}\\cf0\\ulnone\\f0 ";

    _val2 = "\\uc0 ";
    for (int i = 0; i < address.Length; i++)
    {
        _val2 += "\\u" + ((short)address[i]).ToString() + " ";
    }

    _val = s + s1 + _val2 + s2;

    _val2 = "\\uc0 ";
    for (int y = 0; y < text.Length; y++)
    {
        _val2 += "\\u" + ((short)text[y]).ToString() + " ";
    }

    _val += _val2 + s3 + Environment.NewLine + "\\protect0 " + Environment.NewLine + "}";

    this.SelectedRtf = _val;
}


It's not perfect, but working. It uses MS Word style hyperlinks (it uses HYPERLINK keyword defined inside field). After adding the code above provide the link text (caption), address (this is the path to your file) and optionally the color of the link.

One more thing. On my computer there was a problem. Method above worked only if there was some text after the link. Unsure | :~ . It was somehow unexpected. Fortunatly I found the solution. You have to handle the LinkClicked event in the WndProc in the following way:

if (m.Msg == 8270)
{
    NativeMethods.ENLINK lParam;

    lParam = m.GetLParam(typeof(NativeMethods.ENLINK)) as NativeMethods.ENLINK;

    if (lParam != null)
    {
        if (lParam.msg == 513)
        {
            string str = this.CharRangeToString(lParam.charrange);
            if (!string.IsNullOrEmpty(str))
            {
                m.Result = (IntPtr)1;
                OnLinkClicked(new LinkClickedEventArgs(str));
            }
            else base.WndProc(ref m);
        }
        else base.WndProc(ref m);
    }
    else base.WndProc(ref m);
}


It happens that way: user clicks the link, we handle it, than we get its address (this should be you filename) and convert it into a string. After that we rise the OnLinkClicked event and passing the address to it. All you need to do is just to decide what to do it LinkClicked proc. Big Grin | :-D

Fortunately, definition for ENLINK, TEXTRANGE, NMHDR and CHARRANGE you can find in the MSDN. And here is the definitions for CharRangeToString function:

private class CharBuffer
        {
            // Fields
            internal char[] buffer;
            internal int offset;

            // Methods
            internal CharBuffer(int size)
            {
                if (size > 8196 || size < 0)
                {
                    this.buffer = new char[0];
                    return;
                }

                try
                {
                    this.buffer = new char[size];
                }
                catch (Exception)
                {
                }
            }

            public IntPtr AllocCoTaskMem()
            {
                if (this.buffer.Length == 0) return IntPtr.Zero;

                IntPtr destination = Marshal.AllocCoTaskMem(this.buffer.Length * 2);
                Marshal.Copy(this.buffer, 0, destination, this.buffer.Length);
                return destination;
            }

            public string GetString()
            {
                int offset = this.offset;
                while ((offset < this.buffer.Length) && (this.buffer[offset] != '\0'))
                {
                    offset++;
                }
                string str = new string(this.buffer, this.offset, offset - this.offset);
                if (offset < this.buffer.Length)
                {
                    offset++;
                }
                this.offset = offset;
                return str;
            }

            public void PutCoTaskMem(IntPtr ptr)
            {
                Marshal.Copy(ptr, this.buffer, 0, this.buffer.Length);
                this.offset = 0;
            }

            public void PutString(string s)
            {
                int count = Math.Min(s.Length, this.buffer.Length - this.offset);
                s.CopyTo(0, this.buffer, this.offset, count);
                this.offset += count;
                if (this.offset < this.buffer.Length)
                {
                    this.buffer[this.offset++] = '\0';
                }
            }
        }        
        private string CharRangeToString(NativeMethods.CHARRANGE c)
        {
            NativeMethods.TEXTRANGE lParam = new NativeMethods.TEXTRANGE();
            lParam.chrg = c;

            int size = (c.cpMax - c.cpMin) + 1;
            CharBuffer buffer = new CharBuffer(size);
            IntPtr ptr = buffer.AllocCoTaskMem();
            if (ptr == IntPtr.Zero)
            {
                return "";
            }
            lParam.lpstrText = ptr;
            int num1 = (int)NativeMethods.SendMessage(new HandleRef(this, this.Handle), 1099, 0, lParam);
            buffer.PutCoTaskMem(ptr);
            if (lParam.lpstrText != IntPtr.Zero)
            {
                Marshal.FreeCoTaskMem(ptr);
            }
            return buffer.GetString();
        }


I hope this will help you. For me this works perfect. But remember that when you insert the hyperlink that way, you mark it protected, so you can't edit it directly in the RichTextBox. And changing the hyperlinks is another topic.

Good luck.

Cheers,
Alex.

Alex KraS

GeneralRe: Hyperlinks in Advanced Text Editor Pin
frankelman9-Jan-09 8:48
frankelman9-Jan-09 8:48 
QuestionSetting Ruler Margins, Indentations [modified] Pin
Tristan Baron19-Dec-08 1:52
Tristan Baron19-Dec-08 1:52 
GeneralUnable to set rtf property by code Pin
Michael Hachen10-Sep-08 2:12
Michael Hachen10-Sep-08 2:12 
GeneralRe: Unable to set rtf property by code Pin
Aleksei Karimov10-Sep-08 5:29
Aleksei Karimov10-Sep-08 5:29 
GeneralRe: Unable to set rtf property by code Pin
Michael Hachen11-Sep-08 1:58
Michael Hachen11-Sep-08 1:58 
GeneralRe: Unable to set rtf property by code Pin
Aleksei Karimov12-Sep-08 3:53
Aleksei Karimov12-Sep-08 3:53 
QuestionUtility of "old style formating" region ? Pin
moimael6-Sep-08 1:28
moimael6-Sep-08 1:28 
AnswerRe: Utility of "old style formating" region ? Pin
Aleksei Karimov10-Sep-08 5:27
Aleksei Karimov10-Sep-08 5:27 
GeneralRe: Utility of "old style formating" region ? Pin
minhvc21-Sep-08 16:44
minhvc21-Sep-08 16:44 
Questiontranslation to vb2005 Pin
frankelman28-Jul-08 11:08
frankelman28-Jul-08 11:08 
AnswerRe: translation to vb2005 Pin
Aleksei Karimov16-Aug-08 20:45
Aleksei Karimov16-Aug-08 20:45 
GeneralRe: translation to vb2005 Pin
frankelman23-Aug-08 5:01
frankelman23-Aug-08 5:01 
GeneralRe: translation to vb2005 [modified] Pin
nyt197214-Jul-11 23:38
professionalnyt197214-Jul-11 23:38 
GeneralRe: translation to vb2005 Pin
nyt197218-Jul-11 21:48
professionalnyt197218-Jul-11 21:48 
QuestionVisual Basic 2008 Express Edition Pin
mr_fj24-Jul-08 10:46
mr_fj24-Jul-08 10:46 
AnswerRe: Visual Basic 2008 Express Edition Pin
Aleksei Karimov25-Jul-08 2:21
Aleksei Karimov25-Jul-08 2:21 
AnswerRe: Visual Basic 2008 Express Edition Pin
mr_fj26-Jul-08 14:22
mr_fj26-Jul-08 14:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.