Tag Archives: Winforms - Page 2

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!

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.