Winforms HTML Editor control – source code

A lot of people requested the source code, so I put it together in a small VS 2008 solution.

Feel free to download (Link at bottom of post).
Let me know of any problems

Basically what I did is:

  1. I extended this Windows Forms based text editor with HTML output control from Kevin (from codeproject) to use TinyMce as an editor.
  2. With this helpful control  HTML Viewer component from Nikhil
  3. and changed it, see Siag.Seca.WinForms.ServiceBrowser.Controls.Html.HtmlEditor

Reason: We wanted (in our Windows Forms application) to have the same look-and-feel as web users have with the web tinyMce editor.

 

View Mode (the easy part)

The usercontrol "Siag.Seca.WinForms.ServiceBrowser.Controls.Html.HTMLUserControl" is a wrapper around: "HtmlEditor"
Property HTMLUserControl.TextHtml  = my property from datasource

Edit Mode

Prerequisites

  • Subdirectory with tinymce (like on the web) called /tiny_mce
    this folder contains a .html file with the tinymce code
  • TinyEditWithReplace.htm
    that file has a placeholder for the HTML string


Go into Edit Mode

See Siag.Seca.WinForms.ServiceBrowser.Controls.Html.HtmlEditor

Method: cHANGEToolStripMenuItem_Click

using (EditDialog dialogForm = new EditDialog())
    {
        dialogForm.ChangeEditorHtmlText(this.TextHtml);

        if (dialogForm.ShowDialog() == DialogResult.OK)
        {
            this.TextHtml = dialogForm.TextHtml;
        }
    }

 

Siag.Seca.WinForms.ServiceBrowser.Controls.Html.EditDialog

Method: ChangeEditorHtmlText(string htmlTextOnInit)

string absolutePath = Path.GetDirectoryName(Application.ExecutablePath);
    string htmlText = File.ReadAllText(absolutePath + @"TinyEditWithReplace.htm"); // TODO change to use Path.Combine()

    // Now I replace '{ReplaceTEXT}'  with my html string property, and a bit more... :-)
    string filename = Path.GetTempFileName();
    File.WriteAllText(filename, htmlText, Encoding.UTF8);

    htmleditorEdit.NavigateTo(filename);

--> Now the control displays webbrowser.

Inside the webbrower there is tinyMce with the content from my datasource

User can edit the content with TinyMce
--> On OK  Click Handler
i read the string back from webbrowser, tinymce


Advanced

On how to add an attachment link to the HTML (string) see my blog post...

http://peitor.blogspot.com/2007/12/how-to-get-javasrcipt-returnvalue-from.html

 

Screens of my sample app


image
 Figure: Left side: HTML control in view mode - Right side: Source code of the HTMLEditor

 

image
Figure: Clicking on "Edit" brings the control into Edit mode

 

image
Figure: Edit mode (WYSIWYG HTML editor )

 

image
Figure: Example using databinding the control to a grid with HTML content

 

 

More screens can be found here on my older blog entry

 

NOTE

#1
tinyMce: Updated to current version 3.2.7
http://tinymce.moxiecode.com/download.php

#2
Have a look at the file: \SolutionItems\ValidHtmlText.txt   to configure layout of textarea and tinyMCE  

#3
On Build I have a Post build event that copies the tinyMce files and ValidHTMLtext to the output folder…

image

REM ---------------
REM IF "$(ConfigurationName)"=="Release" xcopy /Y /E "$(SolutionDir)SolutionItems\tiny_mce" "$(TargetDir)tiny_mce\" -- DON'T COPY whole tinyMCE on all builds
xcopy /Y /E "$(SolutionDir)SolutionItems\tiny_mce" "$(TargetDir)tiny_mce\"

xcopy /Y /E /i "$(SolutionDir)SolutionItems\tiny_mce\TinyEditWithReplace.htm" "$(TargetDir)tiny_mce\"
xcopy /Y /E /i "$(SolutionDir)SolutionItems\ValidHtmlText.txt" $(TargetDir)

REM ---------------

#4
Deployment problems –> see this blog post

 

disk_blue Download here

arrow_right_blue Please test, let me know of any problems!

arrow_right_blue Free to send suggestions. Make improvements and let me know!

ASP.NET – WTF Code smell – Request.Path.Contains

1. Read the following code and try to understand what it tries to achieve

 protected void Page_Load(object sender, EventArgs e)
 {

       if (HttpContext.Current.User.IsInRole("User "))
       {
           FormView1.FindControl("noteRow").Visible = true;
           FormView1.FindControl("RequiredFieldValidator4").Visible = false;
           // TODO: Fix this - What if Action is 2nd parameter in URL
           if (Request.Path.Contains(@"ClientProfile.aspx?Action=Add"))
           {
               FormView1.FindControl("thLoginID").Visible = true;
               FormView1.FindControl("tdLoginID").Visible = true;
               FormView1.FindControl("txtLoginID").Visible = true;
           }

       }
       else
       {
           FormView1.FindControl("noteRow").Visible = false;
       }


     if (HttpContext.Current.User.IsInRole("Administrator"))
     {

         if (!Request.Path.Contains(@"/AdministratorProfile.aspx"))
         {
             if (!Request.Path.Contains(@"/Profile.aspx"))
             {
                 FormView1.FindControl("txtLoginID").Visible = false;
                 FormView1.FindControl("lblLoginID").Visible = false;
                 -- Snip snip snip – more controls are hidden or shown -- --

                 if (Request.Path.Contains(@"/UserProfile.aspx") && HttpContext.Current.User.IsInRole("User") && (Request.QueryString["Action"] == null || Request.QueryString["Action"].Equals("New")))
                 {

                     FormView1.FindControl("thLoginID").Visible = true;
                     FormView1.FindControl("lblLoginID").Visible = true;
                     -- Snip snip snip – more controls are hidden or shown -- --

                 }
                 else
                 {
                     FormView1.FindControl("thLoginID").Visible = false;
                     FormView1.FindControl("lblLoginID").Visible = false;
                     -- Snip snip snip – more controls are hidden or shown -- --


                 }

             }
             else
             {
                 FormView1.FindControl("thDateRegistered").Visible = false;
                 FormView1.FindControl("tdDateRegistered").Visible = false;
                 -- Snip snip snip – more controls are hidden or shown -- --

             }
         }
         else if (Request.Path.Contains(@"/ReaderProfile.aspx"))
         {
             FormView1.FindControl("tdAdviser").Visible = false;
             FormView1.FindControl("thAdviser").Visible = false;
             -- Snip snip snip – more controls are hidden or shown -- --
 
         }
     }
     else if (HttpContext.Current.User.IsInRole("Administrator"))
     {
        -- Snip snip snip – this code is 130 lines long... -- --

     Figure: Code from a ASP.NET usercontrol. The usercontrol determines on which page it is used

2. Now try to image you have to fix something in this mess.

3. Or try to add a feature for a certain user.

 image

 

The only way this code is developed, is

  1. debugging (called manual testing by Roy)
  2. adding some code,
  3. debugging again,
  4. adding some code

 

My main problem here is the combination of

In particular

  • The check on URL path and query string parameters!!!
  • -->  Request.Path.Contains(@"ClientProfile.aspx?Action=Add")
    • What if Action is 2nd parameter in URL (and not the 1st one)
    • This comes from: debugging and seeing that this comes in to the control…

How can the next dev work out when we enter in which branch?

 

 ap--check   This code (control) has been fixed now and uses now properties that are set from the user of the control

My suggestions:

  • Don’t touch Request.Path.Contains method at all
  • Don’t use debugging to decide which part of the method to insert new code
  • Try to think before code :-)
  • Don’t use the debugger to much

BTW: This code broke at least two principles

  1. Single Responsibility Principle
  2. tell don’t ask principle

 

I am curious so I paste this code to VS 2010 and run “Analyze”, “Code Metrics”

  • Cyclomatic Complexity = 23. Not too bad.  EDIT: Cyclomatic Complexity = 23 = Bad.
  • Maintainability Index = 25. Not very good

 

image Figure: Cyclomatic Complexity of 23 for the Page_Load method

 

As a quick test I extract a piece of code from the Page_Load to another method and expect the Cyclomatic Complexity to go down and the Maintainability to go up.

imageFigure: Extracting 1 method out of Page_Load, “Maintainability Index” goes up - NICE

 

Extract til you drop, but with meaningful names!!!

Latest Posts

Popular Posts