Tag Archives: code - Page 5

MDI interface alternative

As some developers might remember there was a time when Microsoft created/used the MDI type of user interface – MDI stands for Multiple Document Interface in case you forgot. It was widely in use during the Windows 3 and 95 areas and applications like Word, Excel and even Visual Studio used it. And then Microsoft move on… apparently abandoning the use for MDI in their own applications.

Fortunately (sort of) they still support developers creating MDI interface applications in Visual Studio 2010, but for WinForms only. WPF has no native support for it. The real problem is that since Windows 7/Vista came around they don’t actually support the MDI type of interface. Easiest way to see this is that MDI child windows are not rendered with the current Windows theme but instead shown with the ugly ‘default’ Windows theme. This is really a shame. There are still many applications or scenarios where this type of user interface is useful – I’ll admit there are many cases where alternative UI’s are better – like the tabs in web browsers like Firefox and lately IE. However, there is no ‘easy’ way to create applications using a tabbed interface in Visual Studio with all the supported things like Firefox or IE has. For one – dragging, moving and dropping tabs are not supported by default (as in WinForms – not sure about WPF). You cannot ’embed’ child Forms inside tabs (well, actually it might theoretically work as both ‘Forms’ and ‘Controls’ are internally derived from the same classes but it is going to cost some hacking…). Instead, you have to develop your entire Form as a UserControl, which is not a train smash but still…

So I’ve been digging through the Internet (electron by electron it feels like) and saw many others complain and suggesting alternatives. All the complaints aside, there are ways to do things differently but it is going to cost some work! (rolling up sleeves).

I started playing with some code to see what I can do with some trial and error. The basic approach I’m following is to use a plain old WinForm with a tab control on it. Creating tabs dynamically is easy enough in .Net. What is not so easy is the part where you must keep track of the child ‘windows’ and what is where at what time. Basically, you have to rewrite your own mini ‘Window manager’. I’ve got something working that kind of works but it doesn’t look pretty yet. It has the potential to develop into a full new MDI like framework. Keep in mind this is still work in progress and it is not complete.

IChildWindow

In order for the main or parent form to ‘communicate’ with the children and vice versa you need some standard interface. I created IChildWindow for this.

public interface IChildWindow
{

/// <summary>
/// Unique Id if used
/// </summary>
int Id { get; set; }
/// <summary>
/// Type description
/// </summary>
string Type { get; }
/// <summary>
/// Is the tab/Window pinned
/// </summary>
bool Pinned { get; set; }
/// <summary>
/// Start clean up process before closing tab/window
/// </summary>
void CloseAndCleanup();
string GetWindowTitle();
event StartCleanupDelegate StartCloseAndCleanup;
event PinnedStatusChangedDelegate PinnedStatusChanged;

}

This interface is really simple and small. The ‘Id’ and ‘Type’ properties are used to uniquely identify a ‘child window’. Actually, the ‘Id’ is only used for cases where the child can have multiple instances – say you have an editing window for persons then the ‘Id’ would be used for the person id field. In other cases you might want a window that is unique by itself in the application or reused for everything.

Pinned is used to ‘pin’ the window – if you choose ‘Close All tabs’ on the parent window it will not close the pinned tabs.

The CloseAndCleanup method is simply a way to to ensure any resources created/used on the child window gets cleaned up. GetWindowTitle is called to set the display name or text of the tab/window.

UserControlIdentifier

In order to ‘map’ type of ‘windows’ used to a name I created this simple class.

public class UserControlIdentifier
{

public string TypeName { get; set; }
public Type UserControl { get; set; }

}

It identifies the type of ‘window’ or in this case the UserControl.

WindowManager

This is a base class that manages the list of opened ‘windows’. It has methods for finding, creating, opening, and closing ‘windows’. It is generic and does not have a direct link to the type of ‘control’ used to host the new ‘window’ system. Instead, it only reference the IChildWindow interface (and UserControlIdentifier for identifying and creating windows).

The following is just a partial view of the class.

public abstract class WindowManager
{

private List<IChildWindow> windowList = new List<IChildWindow>();
protected abstract void CreateNewWindow(IChildWindow cw);
protected abstract void CloseWindow(IChildWindow cw);
protected abstract void SetWindowFocus(IChildWindow cw);
protected abstract void OnPinnedStatusChanged(IChildWindow cw);

#region Open window

public void OpenChildWindow(UserControlIdentifier uci, int id, bool reUseSimilarType)
{

IChildWindow c = FindChildWindowByTypeAndId(uci, id);
if (c != null)
{

SetWindowFocus(c);

}
else
{

if (reUseSimilarType)
{

c = FindFirstChildWindowOfType(uci);
if (c != null)
{

c.Id = id;
SetWindowFocus(c);
return;

}

}
//The create new window
IChildWindow newChild = CreateChildWindow(uci, id);

}

}
private IChildWindow CreateChildWindow(UserControlIdentifier uci, int id)
{

IChildWindow newChild = (IChildWindow)Activator.CreateInstance(uci.UserControl);
newChild.Id = id;
CreateNewWindow(newChild);
SetWindowFocus(newChild);
newChild.PinnedStatusChanged += new PinnedStatusChangedDelegate(OnPinnedStatusChanged);
newChild.Pinned = false; //and display the unpinned icon
windowList.Add(newChild);
return newChild;

}

#endregion

#region Close window

public void CloseChildWindow(IChildWindow cw)
{

cw.CloseAndCleanup();
windowList.Remove(cw);
CloseWindow(cw);

}

public void CloseAllChildWindows(bool forced)
{

for (int i = windowList.Count – 1; i >= 0; i–)
{

IChildWindow cw = windowList[i];
if (forced || (!cw.Pinned))
{

CloseChildWindow(cw);

}

}

}

#endregion

#region Find window
public IChildWindow FindFirstChildWindowOfType(UserControlIdentifier uci)
{

foreach (IChildWindow c in windowList)
{

if (c.Type == uci.TypeName)
{

return c;

}

}
return null;

}
public IChildWindow FindChildWindowByTypeAndId(UserControlIdentifier uci, int id)
{

foreach (IChildWindow c in windowList)
{

if (c.Type == uci.TypeName && c.Id == id)
{

return c;

}

}
return null;

}
#endregion

#region Pinned status
public void SetChildWindowPinnedStatus(IChildWindow c)
{

c.Pinned = !c.Pinned;

}
#endregion

}

WindowManagerForTabControl

This is the custom implementation of the WindowManager base class. It is created to handle the System.Windows.Forms.TabControl as ‘host’ to the ‘windows’ specifically.

/// <summary>
/// WindowManager implementation for System.Windows.Forms.TabControl
/// Note: the tab control must use an image list control with 3 images
///   image 0: fixed tab
///   image 1: unpinned tab
///   image 2: pinned tab
/// </summary>
public class WindowManagerForTabControl : WindowManager
{

private TabControl hostTabControl;
public WindowManagerForTabControl(TabControl hostTabControl)
{

this.hostTabControl = hostTabControl;

}

protected override void CreateNewWindow(IChildWindow cw)
{

TabPage tp = new TabPage(cw.GetWindowTitle());
((Control)cw).Dock = DockStyle.Fill;
tp.Controls.Add(((Control)cw));
tp.Tag = cw; //set inverse reference
hostTabControl.TabPages.Add(tp);
hostTabControl.SelectTab(tp); //and switch to it

}

protected override void CloseWindow(IChildWindow cw)
{

TabPage tp = null;
foreach (TabPage t in hostTabControl.TabPages)
{

if (t.Tag is IChildWindow && (IChildWindow)t.Tag == cw)
{

tp = t;

}

}
if (tp != null)

hostTabControl.TabPages.Remove(tp);

}

protected override void SetWindowFocus(IChildWindow cw)
{

TabPage tp = null;
foreach (TabPage t in hostTabControl.TabPages)
{

if (t.Tag is IChildWindow && (IChildWindow)t.Tag == cw)
{

tp = t;

}

}
if (tp != null)
{

hostTabControl.SelectTab(tp);
tp.Text = cw.GetWindowTitle();

}

}

protected override void OnPinnedStatusChanged(IChildWindow cw)
{

TabPage tp = null;
foreach (TabPage t in hostTabControl.TabPages)
{

if (t.Tag is IChildWindow && (IChildWindow)t.Tag == cw)
{

tp = t;

}

}
if (tp != null)
{

if (cw.Pinned)

tp.ImageIndex = 1;

else

tp.ImageIndex = 2;

}

}

public IChildWindow GetChildWindowFromTabPage(TabPage tabPage)
{

if (tabPage.Tag is IChildWindow)

return (IChildWindow)tabPage.Tag;

else

return null;

}

}

If you want to use another control or something like WPF’s tab control you would create a similar class for those types.

GlobalChildWindowController

To use all of this you need a singular place to reference the window manager implementation. In order to make it possible to reference this functionality globally in the application it is hosted in a single static class – GlobalChildWindowController.

This is really the ‘run-time’ control center of the implementation. Here the different types of windows get defined and used. The ‘hosting’ main form where the tab control is initialize this class.

public static class GlobalChildWindowController
{

private static WindowManagerForTabControl cwm;
public static void SetHostTabControl(TabControl hostTabControl)
{

cwm = new WindowManagerForTabControl(hostTabControl);

}

//Example window type
public static string PersonWindowTypeName = “Person”;
public static UserControlIdentifier PersonWindowType = new UserControlIdentifier()
{

TypeName = PersonWindowTypeName,
UserControl = typeof(PersonEditControl)

};

public static void OpenPersonWindow(int id, bool reUseCurrent)
{

cwm.OpenChildWindow(GlobalChildWindowController.PersonWindowType, id, reUseCurrent);

}

…

internal static void CloseChildWindow(TabPage tabPage)
{

if (tabPage.Tag != null && tabPage.Tag is IChildWindow)
{

cwm.CloseChildWindow((IChildWindow)tabPage.Tag);

}

}

}

With this class you can make the following call any place in the application:

GlobalChildWindowController.OpenPersonWindow(123);

If there is no existing ‘PersonEdit’ window open one will be opened with Id 123. If you need to have a window reused you the overload OpenPersonWindow(123,true).

ChildWindowBase

Now, to develop one of the ‘client windows’ or in this case a UserControl, I created a base class that inherits from IChildWindow and System.Windows.Forms.UserControl to make it easier to implement (otherwise you’d have to redo all the code for all controls you create.

public class ChildWindowBase : UserControl, IChildWindow
{

#region IChildWindow Members
[System.ComponentModel.Browsable(false)]
public int Id { get; set; }
[System.ComponentModel.Browsable(true),
System.ComponentModel.ReadOnly(true)]
public virtual string Type { get { return “Remember to set this value in derived class!”; } set { } }

public virtual string GetWindowTitle()
{

return string.Format(“{0}”, Type);

}
private bool pinned = false;
[System.ComponentModel.Browsable(true)]
public bool Pinned
{

get { return pinned; }
set
{

pinned = value;
RaisePinnedStatusChanged();

}

}

public event PinnedStatusChangedDelegate PinnedStatusChanged;
private void RaisePinnedStatusChanged()
{

if (PinnedStatusChanged != null)

PinnedStatusChanged(this);

}

public event StartCleanupDelegate StartCloseAndCleanup;
private void RaiseWindowClosing()
{

if (StartCloseAndCleanup != null)
{

StartCloseAndCleanup(this);

}

}
public virtual void CloseAndCleanup()
{

RaiseWindowClosing();

}
#endregion

}

To create a user control you do this:

public partial class SomeChild : ChildWindowBase
{

public SomeChild()
{

InitializeComponent();

}

public override string Type
{

get
{

return GlobalChildWindowController.SomeChildTypeName;

}
set
{

base.Type = value;

}

}

}

Conclusion

As mentioned before, this is a work-in-progress development and may not be perfect – if ever 🙂

Try it out. You can get a preview of it here.

The example shows a person view/edit window that can have multiple instances plus some others that only have a single instance. There is also a dialog box example simulating a search function. Additionally I played with a WPF example that is hosted inside an ElementHost container.

string GetWindowTitle();

HTMLWriter on CodePlex

I’ve decided to move the source code to Codeplex to have it online. This helps with me not having to keep the latest copy on my web site plus it is version controlled.

The Codeplex project is: http://htmlwriter.codeplex.com

But keep on reading my blog… 😉

HTMLWriter 1.3

This is another iteration of my HTMLWriter library. A few new methods  have been added and a whole lot of code comments added for those that like documentation 😉

A new constructor has been added for those that want to enable auto formatting from the beginning.

public HTMLWriter(string documentTitle, bool enableAutoFormatting) : base(documentTitle)
{

AutoFormatting = enableAutoFormatting;
AutoIndentation = enableAutoFormatting;

}

Two new variants of the AppendTagEnd method have been added to make life easier.

public HTMLWriter AppendTagEnd(int tagCountToClose)
{

for (int i = 0; i < tagCountToClose; i++)
{

AppendTagEnd();

}
return this;

}

public HTMLWriter AppendAllEndTagsUntil(string tagName)
{

while (tags.Count > 0)
{

string tagNameToPop = tags.Pop();
AppendTagEndInternal(tagNameToPop, false);
if (tagNameToPop == tagName)

break;

}
return this;

}

Additionally I added the EscapeText method to help format html text properly for characters that might need ‘escaping’.

Find version 1.3 here.

Escaping text in HTML

Thought I just share this little function on its own. I created a simple method that escape (convert) a string to make it ‘safe’ for html display.

public static string EscapeText(string text)
{

string escapeChars2 = @”<>`´àáâãäåèéêëìíîïñòóôõö÷øùúûüýÀÁÂÃÄÅÈÉÊËÌÍÎÏÑÒÓÔÕÖרÙÚÛÜÝ“;

if (string.IsNullOrEmpty(text))

return “”;

else if (text.IndexOfAny(escapeChars2.ToCharArray()) == -1)

return text;

else
{

return text
.Replace(“<“, “&lt;”)
.Replace(“>”, “&gt;”)
.Replace(“&”, “&amp;”)
.Replace(“`”, “&#96;”)
.Replace(“´”, “&acute;”)
.Replace(“à”, “&agrave;”)
.Replace(“á”, “&aacute;”)
.Replace(“â”, “&acirc;”)
.Replace(“ã”, “&atilde;”)
.Replace(“ä”, “&auml;”)
.Replace(“å”, “&aring;”)
.Replace(“è”, “&egrave;”)
.Replace(“é”, “&eacute;”)
.Replace(“ê”, “&ecirc;”)
.Replace(“ë”, “&euml;”)
.Replace(“ì”, “&igrave;”)
.Replace(“í”, “&iacute;”)
.Replace(“î”, “&icirc;”)
.Replace(“ï”, “&iuml;”)
.Replace(“ñ”, “&ntilde;”)
.Replace(“ò”, “&ograve;”)
.Replace(“ó”, “&oacute;”)
.Replace(“ô”, “&ocirc;”)
.Replace(“õ”, “&otilde;”)
.Replace(“ö”, “&ouml;”)
.Replace(“÷”, “&divide;”)
.Replace(“ø”, “&oslash;”)
.Replace(“ù”, “&ugrave;”)
.Replace(“ú”, “&uacute;”)
.Replace(“û”, “&ucirc;”)
.Replace(“ü”, “&uuml;”)
.Replace(“ý”, “&yacute;”)
.Replace(“ÿ”, “&#255;”)
.Replace(“À”, “&Agrave;”)
.Replace(“Á”, “&Aacute;”)
.Replace(“”, “&Acirc;”)
.Replace(“Ô, “&Atilde;”)
.Replace(“Ä”, “&Auml;”)
.Replace(“Å”, “&Aring;”)
.Replace(“È”, “&Egrave;”)
.Replace(“É”, “&Eacute;”)
.Replace(“Ê”, “&Ecirc;”)
.Replace(“Ë”, “&Euml;”)
.Replace(“Ì”, “&Igrave;”)
.Replace(“Í”, “&Iacute;”)
.Replace(“Δ, “&Icirc;”)
.Replace(“Ï”, “&Iuml;”)
.Replace(“Ñ”, “&Ntilde;”)
.Replace(“Ò”, “&Ograve;”)
.Replace(“Ó”, “&Oacute;”)
.Replace(“Ô”, “&Ocirc;”)
.Replace(“Õ”, “&Otilde;”)
.Replace(“Ö”, “&Ouml;”)
.Replace(“×”, “&times;”)
.Replace(“Ø”, “&Oslash;”)
.Replace(“Ù”, “&Ugrave;”)
.Replace(“Ú”, “&Uacute;”)
.Replace(“Û”, “&Ucirc;”)
.Replace(“Ü”, “&Uuml;”)
.Replace(“Ý”, “&Yacute;”);

}

}

There are other ways to do the string matching – like Regular Expressions, but they add some other overhead for a method that does something simple like this.

HTMLWriter 1.2

And with another iteration the library has improved yet again. See the previous or original posts for details about where it came from.

With this version I’ve made some big changes internally to the library. You can still use the basic functionality as with version 1.0 but the auto indentation has been improved greatly – and simplified in the code. Essentially it now properly formats the generated html with indentation for tags specified to do so.

To make it much easier to manage auto formatting tags I modified the AppendTagStart and AppendTagEnd methods to make use of some string arrays that define tags that require standard behavior – like always insert a crlf in-front of it or always append crlf etc.

The arrays looks like this:

startTagsAutoOnNewLine = new string[]
{

“address”,
“blockquote”,
“code”,
“div”,
“h1″,”h2″,”h3″,”h4″,”h5″,”h6”,
“iframe”,
“ol”, “ul”, “dl”,
“table”, “thead”, “tfoot”, “tbody”, “tr”, “td”, “th”

};

tagsAutoIncDecIndentation = new string[]
{

“address”,
“blockquote”,
“ol”, “ul”, “dl”,
“table”, “thead”, “tfoot”, “tbody”, “tr”

};

endTagsAutoOnNewLine = new string[]
{

“address”,
“blockquote”,
“ol”, “ul”, “dl”,
“table”, “thead”, “tfoot”, “tbody”, “tr”,

};

endTagsAutoAppendCRLF = new string[]
{

“address”,
“blockquote”,
“code”,
“h1″,”h2″,”h3″,”h4″,”h5″,”h6”,
“iframe”,
“ol”, “ul”, “dl”,
“table”

};

The 2 methods look like this:

protected void AppendTagStartInternal(string tagName, string className, params CustomAttribute[] customAttributes)
{

if (AutoFormatting)
{

if (startTagsAutoOnNewLine.Contains(tagName.ToLower()))
{

AppendNewLineInternal();
AppendIndentation();

}
else if (lastWrittenCRLF)
{

AppendIndentation();

}

}
this.AppendInternal(string.Format(“<{0}”, tagName));
if (className.Length > 0)

this.AppendInternal(string.Format(” class=\”{0}\””, className));

foreach (CustomAttribute customAttribute in customAttributes)
{

this.AppendInternal(” ” + customAttribute.ToString());

}
this.AppendInternal(“>”);
tags.Push(tagName);
if (AutoFormatting)
{

if (tagsAutoIncDecIndentation.Contains(tagName.ToLower()))
{

IndentationInc();
AppendNewLineInternal();

}

}

}

protected void AppendTagEndInternal(string tagName, bool autoPop)
{

if (autoPop && tags.Peek() == tagName)

tags.Pop();

if (AutoFormatting)
{

if (tagsAutoIncDecIndentation.Contains(tagName.ToLower()))
{

IndentationDec();

}
if (endTagsAutoOnNewLine.Contains(tagName.ToLower()))
{

AppendNewLineInternal(); ;
AppendIndentation();

}
else if (lastWrittenCRLF)
{

AppendIndentation();

}

}

this.AppendInternal(“</” + tagName + “>”);

if (AutoFormatting)
{

if (endTagsAutoAppendCRLF.Contains(tagName.ToLower()))
{

AppendNewLineInternal();

}

}

}

Additionally I split the HTMLWriter class into 2 – the plain HTMLWriter and a base class – HTMLWriterBase. The reason is simple – it makes it easier to maintain core/internal functionality separately but also allow for another custom implementation of another type of xyzWriter.

The DataTable specific methods were also enhanced to allow for a hyperlink (anchor tag) to be embedded based on one of the fields inside the DataTable. It allows you to specify an editing page, the parameter name passed to the page, the linked id field from the DataTable and the display field in which the link will be placed.

Available here.

HTMLWriter 1.1

A few days ago I published the original HTMLWriter article. Since then I’ve added a few methods to make simple formatting easier. This includes a way to specify an ‘indentation’ level. Right now it is pretty basic but it helps making some html tags like tables easier to read.

The most important methods added are these:

private void AppendInternalCRLF()
{

sbHtmlContent.Append(“\r\n”);
lastWrittenIndentation = false;

}

private void AppendInternalIndentation()
{

sbHtmlContent.Append(new string(‘\t’, Indentation));
lastWrittenIndentation = true;

}

public HTMLWriter AppendNewLine()
{

this.AppendInternalCRLF();
return this;

}
public HTMLWriter AppendNewLineWithIndentation()
{

if (AutoFormatting && !lastWrittenIndentation)

return this.AppendNewLine().AppendIndentation();

else

return this;

}

The lastWrittenIndentation variable is there since some html tags can call this method at the beginning and the end. If the next tag also starts by calling the method again then it ignores the method to avoid duplicating the indentation.

An example of one of the methods using it:

public HTMLWriter AppendTableStart(string className, params CustomAttribute[] customAttributes)
{

AppendNewLineWithIndentation();
return AppendTagStart(“table”, className, customAttributes);

}

Then I played around trying to ‘Normalize’ the html by using a library I discovered on CodePlex a while ago – System.Html

There seems to be a little issue using this library of the html is condensed (i.e. no CRLFs) but that is solved by cheating and replacing all ‘><‘ characters with ‘>\r\n<‘ .

Please keep in mind that this library was created to create simple html fragments or documents – mainly to generate reports inside a normal Winforms application.

The updated library can be found here.

 

 

HTMLWriter

Sometimes you might need to use a technology in a way it wasn’t intended because it has some features that you find useful. Displaying html in a web browser control inside a Winforms application can be useful because it provides built-in support things like printing and exporting data.

There are multiple ways to generate html source code – some ways are not recommended like concatenating strings or even hard-coding text inside the application. A few years ago I came across a library to write RTF (Rich Text Format) that gave me an idea how to write a small little utility class to create html fragments or even documents.

The main goal of the library is to make it easy to create html fragments without much code from the calling application but allow it to be flexible enough to be extended if needed. Internally it use a StringBuilder so it creates a mutable string that makes it much more efficient in handling larger fragments of text/html.

The heart of the library/class is one method:

private void AppendInternal(string value)
{

if (!string.IsNullOrEmpty(value))

{

sbHtmlContent.Append(value);

}

}

Then the rest of the methods follow the pattern – call the AppendInternal in various ways to generate the final html e.g.

public HTMLWriter AppendRAW(string tagName)
{

this.AppendInternal(tagName);
return this;

}

One additional thing you might notice is that the method returns a reference to the containing class. This is a useful  trick so you can queue up methods to group them together if they all contribute to one common goal.

Then you have to remember that html (like xml and other markup languages) require (most) elements/tags to have corresponding closing tags. To make it easier to ‘remember’ what html tag needs to be closed there is a stack object that stores the appended tags that get ‘pop’ of the stack when the AppendTagEnd() method gets called.

There is also a CustomAttribute helper class to help add custom attributes for some html tag that requires it. Think about the href attribute for the anchor (<a >) tag or colspan/rowspan attributes for the td tag.

To illustrate these points look at the following methods:

public HTMLWriter AppendTagStart(string tagName, string className, params CustomAttribute[] customAttributes)
{

this.AppendInternal(string.Format(“<{0}”, tagName));
if (className.Length > 0)

this.AppendInternal(string.Format(” class=\”{0}\””, className));

foreach (CustomAttribute customAttribute in customAttributes)
{

this.AppendInternal(” ” + customAttribute.ToString());

}
this.AppendInternal(“>”);
tags.Push(tagName);
return this;

}

public HTMLWriter AppendTagEnd()
{

if (tags.Count > 0)
{

string tagName = tags.Pop();
this.AppendInternal(“</” + tagName + “>”);

}
return this;

}

Now using these methods to create – say the anchor tag, would look like this:

public HTMLWriter AppendAnchorStart(string url, string className, string title)
{

return AppendTagStart(“a”, className,
new CustomAttribute(“href”, url),
new CustomAttribute(“title”, title);

}

If you want to create full html documents it also provides support for stylesheets. This is handled similarly, but separately with a StringBuilder class that is combined when you call the final ToString() method to retrieve the whole html document.

As a final example look at the following piece of code to create a table:

HTMLWriter h = new HTMLWriter(“Test”);

h.AppendTableStart(“main”, new CustomAttribute(“border”, “0”))
.AppendTableRowStart()
.AppendTableHeaderCellStart()
.AppendRAW(“Name”)
.AppendTagEnd()
.AppendTableHeaderCellStart()
.AppendRAW(“Surname”)
.AppendTagEnd()
.AppendTagEnd()
.AppendTableRowStart()
.AppendTableCellStart(“”, new CustomAttribute(“colspan”, “2”))
.AppendRAW(“test2”)
.AppendTagEnd()
.AppendTagEnd()
.AppendTagEnd();

The output looks like this:

<table class=”main” border=”0″><tr><th>Name</th><th>Surname</th></tr><tr><td colspan=”2″>test2</td></tr></table>

Finally (for now) there is an extension to the class (since it is a partial class) that can handle DataTable objects (like in DataSets). It makes it possible to simply pass a DataTable object to the library and it generates a complete html table with column names, rows and even alternating background colors for rows.

If you like you can download and try the library (at your own risk 😉 ). Find it here.

Update: using this library you can reference only the Framework Client Profile oppose to the full .Net framework. This can help to reduce the total download/install size.

Update: if you need to Normalize html nicely you can use another library you can find at http://systemhtml.codeplex.com.

Fading Windows form in and out

I’ve been using a little class for years to make Windows Forms fade in and out using the built-in OS features. This makes it far more powerful than just playing with the opacity. Using it is also very easy as it is a self contained class that already inherits from System.Windows.Forms.Form. This means all you have to do to use it is inherit from it and everything else is done for you already.

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace HenIT.Windows.Forms
{

public class FadeForm : Form
{

#region Constants
const int AW_HIDE = 0X10000;
const int AW_ACTIVATE = 0X20000;
const int AW_HOR_POSITIVE = 0X1;
const int AW_HOR_NEGATIVE = 0X2;
const int AW_SLIDE = 0X40000;
const int AW_BLEND = 0X80000;
const int FADEINTIMEMS = 500;
const int FADEOUTMS = 250;
#endregion

[DllImport(“user32.dll”, CharSet = CharSet.Auto)]
private static extern int AnimateWindow
(IntPtr hwand, int dwTime, int dwFlags);

private bool _UseSlideAnimation;
public FadeForm() : this(false) { }
public FadeForm(bool useSlideAnimation)
{

_UseSlideAnimation = useSlideAnimation;

}

#region Overrides
protected override void OnLoad(EventArgs e)
{

base.OnLoad(e);
AnimateWindow(this.Handle, FADEINTIMEMS, AW_ACTIVATE | (_UseSlideAnimation ?
AW_HOR_POSITIVE | AW_SLIDE : AW_BLEND));
this.Refresh();

}

protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{

base.OnClosing(e);
if (e.Cancel == false)
{

AnimateWindow(this.Handle, FADEOUTMS, AW_HIDE | (_UseSlideAnimation ?
AW_HOR_NEGATIVE | AW_SLIDE : AW_BLEND));

}

}

#endregion

}

}

And that is it!

Another use for .Net Generics

Some time ago I created a simple utility class to quickly serialize and deserialize objects at run-time. It worked ok but had one drawback (probably more but I’m dealing with one specific one here). Because it deals with objects at run time and before the advent of generics you had to pass the object type as a parameter around – possibly I could have kept it dealing with only objects but I was trying to make the calling code easier to maintain and read.

The old methods looked something like this:

static class SerializeUtils
{

public static string SerializeXML(object classToSerialize)
{

XmlSerializer ser = new XmlSerializer(classToSerialize.GetType());
StringBuilder sb = new StringBuilder();
StringWriter writer = new StringWriter(sb);
ser.Serialize(writer, classToSerialize);
return sb.ToString();

}
public static object DeserializeXML(string serializedObject, System.Type typeOfObject)
{

XmlSerializer ser = new XmlSerializer(typeOfObject);
MemoryStream input = null;
object result = null;
input = new MemoryStream(System.Text.Encoding.Unicode.GetBytes(serializedObject));
input.Position = 0;
result = ser.Deserialize(input);
return result;

}

}

But then at one stage I thought why must the object type be passed as a parameter plus the calling code still has to cast it again. Thankfully Generics make all that easier. Look at this:

public static class SerializationUtils
{

public static string SerializeToXML<T>(T classToSerialize) where T : class
{

XmlSerializer ser = new XmlSerializer(typeof(T));
StringBuilder sb = new StringBuilder();
StringWriter writer = new StringWriter(sb);
ser.Serialize(writer, classToSerialize);
return sb.ToString();

}

public static T DeserializeXML<T>(string serializedObject) where T : class
{

XmlSerializer ser = new XmlSerializer(typeof(T));
MemoryStream input = null;
T result = null;
input = new MemoryStream(System.Text.Encoding.Unicode.GetBytes(serializedObject));
input.Position = 0;
result = (T)ser.Deserialize(input);

return result;

}

}

In a way the methods still take the type as a ‘parameter’ but this is something the compiler can use at compile time as well – i.e. to make sure the input and return types are actually of the proper class. With the Deserialized method the calling code actually get a fully casted object back.

There you have it.

ListViewColumnSorter

On my previous blog(the one on ‘that’ site that just went AWOL…) I had an article and download link to a class that I often used for making sorting easier in a ListView control. It drew some attention even with some people at Microsoft themselves.

Of course times have passed and even MS these days seems to be moving away from Winforms but I have yet to make any real effort to start moving to WPF – there are reasons for this… Anyway,  I’m sure there are people that still use Winform development and a class like this one could be very useful.

Functionality

Since the original I have made some changes (hopefully improvements). For those that don’t remember or missed it originally, here is a list of (the original) functionality that it provides:

  • It implements the standard IComparer interface that is required for making a custom class for sorting a ListView control (in detail view).
  • It defines some standard types of sorting (plain string, number, date, byte sizes, inverted strings and number/string mix)
  • It can automatically ‘bind’ to the column clicking event meaning you don’t have to write a single line of code to do the sorting stuff yourself (provided you use one of the provided standard sorting types)
  • It adds the little triangle icons to the clicked column header indicating sort direction.
  • It allows for disabling/enabling of sorting. This helps while you are loading the control and do not want the sorting/comparing routines firing for each insert!
  • Using it is very easy. All it requires to get started is a declaration to it and instantiation. That is 2 lines of code you have to write to use and bind it!

Since the original version I now have added the following functionality:

  • Added 2 new column ‘types’ that are not actually types but a way to add behavior. These are ‘Override’ and Deferred. More on the details on what they do later.
  • The ListView control has the ability to use ‘Groups’ so new functionality has been added to make use of it.

Usage

Like mentioned above to use it is really easy. All you need are ‘2’ lines of code like this:

private ListViewColumnSorter lvwSorter;

private void MainForm_Load(object sender, EventArgs e)
{

//The following lines are actually all one line wrapped for easier reading

lvwSorter = new ListViewColumnSorter(lvwMyListView, true,
SortColumnTypes.StringType,
SortColumnTypes.NumberType,
SortColumnTypes.DateType,
SortColumnTypes.ByteSize,
SortColumnTypes.Override,
SortColumnTypes.Deferred);

}

That is all that is required to get it up and running.

New functionality

Except for the ListView grouping functionality (which I’m not going to cover for now) there are two new related things that have been added to to the control – Override and Deferred sorting.

Deferred sorting

Sometimes you need to sort the ListView based on some other criteria than the displayed column that the user has clicked on. It could be that the displayed values are incomplete or that values in other columns might have to be taken in consideration as well. You may even want to do some external (to the ListView control) look-up in the sorting process. Deferred sorting is the solution to this problem.

The way this functionality work is by using delegates. This way the ListViewColumnSorter control effectively allows you to provide your own custom function that it will call during the sorting process. Keep in mind it will do this for every row in the ListView in the sorting process!

The delegate requires your method to accept 3 paramerters – column number, list view item 1 and list view item 2. As you can guess the column number is the column clicked on and the 2 list view items the items (rows) that must/can be compared. I often attach a custom class to the tag property of the list view item that contains more properties that what is displayed in the ListView. This way you can use the custom class as part of the comparison process. Yes, the ‘unboxing’ of the classes from type object like stored in the tag property does add some overhead so you’re not going to be using this on huge lists (not if you are doing some kind of complex sorting anyway!)

Example code

This example sample simply shows how the deferred method works. It must return the same -1/0/1 return value that the CompareTo method expect.

Somewhere (e.g. in the Form_Load event you can set:

lvwSorter = new ListViewColumnSorter(lvwListView, true, SortColumnTypes.Deferred, …);

lvwSorter.DeferredCompare = DeferredCompare;

Then somewhere else you can define the following method

private int DeferredCompare(int columnToSort, ListViewItem x, ListViewItem y)
{

if (columnToSort == 0)

{

CustomClass customClassX = (CustomClass)x.Tag;

CustomClass customClassY = (CustomClass)y.Tag;

return customClassX.SomeProperty.CompareTo(customClassY.SomeProperty);

}

else

return 0; //or whatever

}

Override

This is actually not really a way to sort the control at all but really to capture the column click event and call a custom method you provide and do anything else (including sorting or reloading the ListView control). This could be useful if you need to do some kind functionality that is too complex for sorting or got nothing to do with sorting at all.

As with deferred sorting this is done by delegates (actually an event in this case). You provide a method that the control will call when that column is clicked.

Example code

Somewhere in the Form_Load event you can set:

lvwSorter = new ListViewColumnSorter(lvwListView, true, SortColumnTypes.Override, …);

lvwSorter.OverrideColumnClicked += new OverrideColumnClickedDelegate(lvwSorter_OverrideColumnClicked);

Then you can define a method like this:

private void lvwSorter_OverrideColumnClicked(int column, SortOrder sortOrder)
{

if (column == 0)

{

DoSomethingElse();

}

}

Download

You can find a copy of the source code here.