Tag Archives: C# - Page 5

Multilingual applications

Living in the good old S of A it is natural for us to be bilingual or even multilingual. So what do we do if we have to create software that can/must be used by people of multiple language backgrounds? Traditionally Microsoft had the concept of resource files that you can use to create multiple versions of the same application for different languages or locales. Problem with this is once the executable has been compiled it is also fixed. What happens if you want the application to be multilingual at ‘run-time’?

Well, I’ve had to do something like this for myself. I first looked at resource files but it just did not solve the whole issue on its own. So I started creating something for myself that works for my application. Part of the solution still use .Net resource files for storing xml data that gets use in the language look up procedure. The idea is to load the text of controls and windows at the time the window open since control and window text get loaded at run-time anyway. The following is an explanation of the classes I created to facilitate my solution. It is a fully working solution and already in use inside a proper application. There may be other and even better or smarter solutions ‘out there’ but this one works for me.

LanguageHandler

This is the central class that handles all the language setting/reading etc. functionality. It encapsulate the list of ‘phrases’ used in the application and provides methods to retrieve words or phrases depending on a look-up key. Simply translating words alone is not good enough so the focus is on whole ‘phrases’.

The following is a partial view of the class without methods:

public static class LanguageHandler
{

private static List<Phrase> phraseList = new List<Phrase>();

#region Properties
private static string languageID = “en-za”;
public static Language AppLanguage {

get {

switch (languageID) {
case “af”:
return Language.Afrikaans;
case “en-za”:
return Language.English;
default:
return Language.Afrikaans; }

}
set {

switch (value) {
case Language.Afrikaans:
languageID = “af”;
break;
case Language.English:
languageID = “en-za”;
break;
default:
languageID = “en-za”;
break; }

}

public static string PhraseSource { set; get; }
#endregion

}

PhraseList.xml

The definition of the phrases can probably be stored in any data form but I choose a plain simple xml file to host the raw phrase data. This make it easy to maintain and port. It is also included into the application as a file resource although theoretically it could be located anywhere as long as the application can reach it.

The structure is also very basic as it is simply a serialized version of List<Phrase>

<?xml version=”1.0″ encoding=”utf-16″?>
<ArrayOfPhrase xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=”http://www.w3.org/2001/XMLSchema”>
<phrase id=”someId” default=”Some default”>

<phraseEntry lang=”af”>Afrikaanse waarde</phraseEntry>
<phraseEntry lang=”en-za”>English value</phraseEntry>

</phrase>
<phrase id=”someId2″ default=”Some default 2″>

…

</ArrayOfPhrase>

LoadPhrases method

Loading the data is as simple as deserializing the data. I have a helper class (not shown) to simply take the xml file and deserialize it:

#region LoadPhrases
public static void LoadPhrases()
{

if ((PhraseSource != null) && (PhraseSource.Length > 0))

phraseList = SerializationUtils.DeserializeXML<List<Phrase>>(PhraseSource);

}
#endregion

GetLanguagePhrase method

The main (and only relevant) method for retrieving stuff from the class is GetLanguagePhrase. It simply takes one parameter – the id value of the phrase required.

#region GetLanguagePhrase
public static string GetLanguagePhrase(string languagePhraseID)
{

if (phraseList.Count == 0)

LoadPhrases();

Phrase phrase = (from p in phraseList where p.LanguagePhraseID == languagePhraseID select p).FirstOrDefault();
if (phrase != null)
{

PhraseEntry phraseEntry = (from pe in phrase.Phrases where pe.LangId == languageID select pe).FirstOrDefault();
if (phraseEntry != null)

return phraseEntry.Text;

else

return phrase.DefaultValue;

}
throw new Exception(“Undefined language phrase ID”);

}
#endregion

SetControlTextAndTip methods

To make it a bit easier to set the text (and tooltips if available) of controls (my implementation use WinForms) I created a few helper methods to automatically set the text on the control based on a phrase id specified.

#region SetControlText
public static void SetControlTextAndTip(string languagePhraseID, params ToolStripItem[] tsis)
{

string text = GetLanguagePhrase(languagePhraseID);
foreach (ToolStripItem tsi in tsis)
{

tsi.Text = text;
tsi.ToolTipText = text;

}

}
public static void SetControlTextAndTip(string languagePhraseID, params Control[] crtls)
{

string text = GetLanguagePhrase(languagePhraseID);
foreach (Control crtl in crtls)
{

crtl.Text = text;

}

}
public static void SetControlTextAndTip(string languagePhraseID, params ColumnHeader[] columnHeaders)
{

string text = GetLanguagePhrase(languagePhraseID);
foreach (ColumnHeader ch in columnHeaders)
{

ch.Text = text;

}

}
#endregion

The Phrase and PhraseEntry classes

These two classes are really simple. For the purpose of this article they could be a lot simpler but since I built a separate ‘editor’ they have a bunch of attributes to make editing easier. This editor plus a few method inside LanguageHandler will have to wait for another article.

[Serializable, XmlType(“phrase”)]
public class Phrase : IComparable
{

[XmlAttribute(“id”),
Browsable(true),
CategoryAttribute(“Identifier”),
DefaultValueAttribute(“”),
DescriptionAttribute(“Phrase ID”),
ReadOnly(true)]
public string LanguagePhraseID { get; set; }
[XmlElement(“phraseEntry”),
Browsable(true),
CategoryAttribute(“Value details”),
DefaultValueAttribute(“”),
DescriptionAttribute(“Phrase entries”)]
public List<PhraseEntry> Phrases { get; set; }
[XmlAttribute(“default”),
Browsable(true),
CategoryAttribute(“Value details”),
DefaultValueAttribute(“”),
Editor(typeof(MultilineStringEditor), typeof(UITypeEditor)),
DescriptionAttribute(“Default value. Use ‘\\r\\n’ to indicate crlf.”)]
public string DefaultValue { get; set; }

#region IComparable Members
public int CompareTo(object obj)
{

Phrase otherPhrase = (Phrase)obj;
return LanguagePhraseID.CompareTo(otherPhrase.LanguagePhraseID);

}
#endregion

}

[Serializable, XmlType(“entry”), TypeConverter(typeof(PhraseEntryConverter))]
public class PhraseEntry
{

public PhraseEntry() { }
public PhraseEntry(string phraseEntryDef)
{

if (phraseEntryDef.Contains(“:”))
{

LangId = phraseEntryDef.Substring(0, phraseEntryDef.IndexOf(“:”));
Text = phraseEntryDef.Substring(phraseEntryDef.IndexOf(“:”) + 1);

}

}

[XmlAttribute(“lang”),
Browsable(true),
CategoryAttribute(“Phrase entry”),
DefaultValueAttribute(“”),
DescriptionAttribute(“Language”)]
public string LangId { get; set; }
[XmlText(),
Browsable(true),
CategoryAttribute(“Phrase entry”),
DefaultValueAttribute(“”),
Editor(typeof(MultilineStringEditor), typeof(UITypeEditor)),
DescriptionAttribute(“Text”)]
public string Text { get; set; }

public override string ToString()
{

return LangId + “:” + Text;

}

}

Using it all

Using LanguageHandler is really easy. Typically in a form’s onload event I call a private local method that sets all the texts of the controls that need to be set. There is no real performance issue to worry about since all the phrase data is stored in memory. One disadvantage is that normally the form need to be closed and reopened if the ‘language’ has change. This is not really a problem since changing the language is something that should not happen often. Technically this private LoadLanguageResources method could be ran any number of times whenever you want. The only place where I usually call it multiple times is on the ‘Options’ dialog where you choose the language being used.

If you have to use the same phrase multiple times you can always store the value in a local string variable.

The following is a short example of how to use it:

static class Program
{

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{

…
if (Properties.Settings.Default.LanguageID == “English”)

LanguageHandler.AppLanguage = Language.English;

else

LanguageHandler.AppLanguage = Language.Afrikaans;

LanguageHandler.PhraseSource = Properties.Resources.PhraseList;
LanguageHandler.LoadPhrases();
…
Form mainForm = new MainForm();
…
Application.Run(mainForm);

}

public partial class MainForm : Form
{

….

private void LoadLanguageResources()
{

Text = LanguageHandler.GetLanguagePhrase(“AppName”);
LanguageHandler.SetControlTextAndTip(“File”, fileToolStripMenuItem);
LanguageHandler.SetControlTextAndTip(“NewPerson”, newPersoonToolStripMenuItem);
…

}

private void MainForm_Load(object sender, EventArgs e)
{

LoadLanguageResources();
…

}

…

}

Summary

As you can see the solution is not really complicated. I really like simple solutions that ‘just works’. This one has proven to be working for my needs so far. I have over 340 different phrases, some are very long themselves like message box prompts.

Check if user is in AD group

This is an action that often is required when you want to make sure a user account may access some resource only if they are part of some AD (OU) group. There are other ways to do this – if fact it is a lot easier if you use newer versions on the .Net framework (like 3.5 and later) but I had to create something that will still work with the 2.0 framework – thanks to some older 2003 servers that I have to manage.

I’m not going to explain too much details on how it works internally – the simple explanation is that I take the user account and loop through the list of groups the user is a ‘memberOf’. One tricky thing is to also cater for cross domain accounts/groups – like when you have a dev domain that also have groups but the user account is part of the live domain – or some combination like it.

A solution

The solution is a single helper class with one public method – IsUserInGroup(string userName, string groupName). Creating an instance of a class with one method is a bit of a waste so the class is a simple static class.

public static class DirectoryServicesHelper
{

private static bool useDomainName = false;

public static bool IsUserInGroup(string userName, string groupName)
{

useDomainName = userName.Contains(“\\”) || groupName.Contains(“\\”);
List<string> userGroups = GetGroupsForUser(userName);
if (userGroups.Contains(groupName.ToLower()))

return true;

return false;

}

The ‘useDomainName’ variable is there simply to indicate to other methods if they must cater for domain level details or not. Most of the rest of the code is inside the private ‘GetGroupsForUser’ method.

private static List<string> GetGroupsForUser(string pstrUser)
{

List<string> lstGroups = new List<string>();

string domain = System.DirectoryServices.ActiveDirectory.Domain.GetCurrentDomain().Name;
DirectoryEntry rootEntry;
if (useDomainName && pstrUser.Contains(“\\”))
{

domain = pstrUser.Substring(0, pstrUser.IndexOf(“\\”));
pstrUser = pstrUser.Substring(pstrUser.IndexOf(“\\”) + 1);

}
rootEntry = new DirectoryEntry(“LDAP://” + domain);

using (DirectorySearcher searcher = new DirectorySearcher(rootEntry, “objectCategory=User”))
{

searcher.Filter = string.Format(“(SAMAccountName={0})”, pstrUser);
SearchResult objSR = searcher.FindOne();
if (objSR != null)
{

using (DirectoryEntry objUser = new DirectoryEntry(objSR.Path))
{

System.DirectoryServices.PropertyCollection colProperties = objUser.Properties;
PropertyValueCollection colPropertyValues = colProperties[“memberOf”];
foreach (string strGroup in colPropertyValues)
{

lstGroups.Add(GetSAMAccountName(strGroup).ToLower());

}

}

}

}
return lstGroups;

}

private static string GetDomainNameFromDE(DirectoryEntry entry)
{

if (entry == null)

return “”;

else
{

if (entry.SchemaClassName == “domainDNS”)

return entry.Properties[“Name”].Value.ToString();

else if (entry.Parent != null)

return GetDomainNameFromDE(entry.Parent);

else

return “”;

}

}

private static string GetSAMAccountName(string pstrPath)
{

DirectoryEntry objADEntry = null;
string output = “”;
objADEntry = new DirectoryEntry(“LDAP://” + pstrPath);
if (objADEntry != null)
{

if (useDomainName)

output = GetDomainNameFromDE(objADEntry) + “\\” + objADEntry.Properties[“SAMAccountName”].Value.ToString();

else

output = objADEntry.Properties[“SAMAccountName”].Value.ToString();

}
return output;

}

Summary

I’ve excluded any error checking to make the code simpler to read. For a real utility class you need to add it since AD is an unmanaged resource (as far as .Net goes) and it can throw COM+ errors as well.

With this little helper class you can simply pass it a user and group name and it will return a true or false if the user is part of the group. I’ve tested it with no domain details, partial domain details, mixed domains etc. Hopefully it can help someone else as well.

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!