Monthly Archives: December 2006

Print a Control

A while ago i discovered the DrawToBitmap method on the Control class. The availability of this method makes it relatively easy to implement a PrintPageEventHandler for the PrintDocument class. Here is an example implementation that prints a DataGridView:

private void buttonPrint_Click(object sender, EventArgs e)
{
 this.printDocument1.Print();
}

void printDocument1_BeginPrint(object sender, PrintEventArgs e)
{
 this.currentPage = 0;
}

private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
 Size oldSize = this.dataGridView1.Size;
 this.dataGridView1.Height = Math.Max(this.dataGridView1.Height, this.dataGridView1.PreferredSize.Height);
 this.dataGridView1.Width = Math.Max(this.dataGridView1.Width, this.dataGridView1.PreferredSize.Width);

 int requiredPagesForWidth = ((int)this.dataGridView1.Width / e.MarginBounds.Width) + 1;
 int requiredPagesForHeight = ((int)this.dataGridView1.Height / e.MarginBounds.Height) + 1;
 int requiredPages = requiredPagesForWidth * requiredPagesForHeight;
 e.HasMorePages = (this.currentPage < requiredPages - 1);

 int posX = ((int)this.currentPage % requiredPagesForWidth) * e.MarginBounds.Width;
 int posY = ((int)this.currentPage / requiredPagesForWidth) * e.MarginBounds.Height;

 Graphics graphics = e.Graphics;
 Bitmap bitmap = new Bitmap(this.dataGridView1.Width, this.dataGridView1.Height);
 this.dataGridView1.DrawToBitmap(bitmap, this.dataGridView1.Bounds);
 graphics.DrawImage(bitmap, new Rectangle(e.MarginBounds.X, e.MarginBounds.Y, e.MarginBounds.Width, e.MarginBounds.Height), new Rectangle(posX, posY, e.MarginBounds.Width, e.MarginBounds.Height), GraphicsUnit.Pixel);

 this.dataGridView1.Size = oldSize;
 ++this.currentPage;
}

Now that you understand the main idea, let’s wrap it in a class and make it reusable: ResizedControlPrintPageEventHandler. Using this class is as simple as:

// Initialise a controlPrintPageEventHandler and register the PrintPage method...
ResizedControlPrintPageEventHandler resizedControlPrintPageEventHandler = new ResizedControlPrintPageEventHandler(this.dataGridView1);
this.printDocument1.PrintPage += resizedControlPrintPageEventHandler.PrintPage;

// Print the control
private void buttonPrint_Click(object sender, EventArgs e)
{
 this.printDocument1.Print();
}

// Give the user a preview
private void buttonPreview_Click(object sender, EventArgs e)
{
 this.printPreviewDialog1.Show();
}

Here are a couple of screenshots:

Screenshot of demo application that has a datagridview with scrollbars.
Screenshot of print preview. Notice that the scrollbars are gone.
Screenshot of the print document.

Feel free to download the class and demo application: ControlPrintPageEventHandler.zip.

An example of why i don't like the ext/filter API

Earlier this week i decided to experiment with the Filter functions. Here’s an example that illustrates why i think the API needs to be improved:

<?php
$isgoodapi = filter_input(INPUT_GET, 'isgoodapi', FILTER_VALIDATE_BOOLEAN);

if (is_null($isgoodapi)) {
 echo "the 'isgoodapi' argument is missing.";
} else if ($isgoodapi === FALSE) {
 echo "The 'isgoodapi' argument must be a valid boolean.";
} else {
 echo "isgoodapi is: $isgoodapi.";
}
?>

And now you request the page with ?isgoodapi=false. The obvious problem is the fact that the function returns multiple ‘sorts’ of return values: Value of the requested variable on success, FALSE if the filter fails, or NULL if the variable_name variable is not set. If the flag FILTER_NULL_ON_FAILURE is used, it returns FALSE if the variable is not set and NULL if the filter fails.

The documentation for Filter Functions says for FILTER_VALIDATE_BOOLEAN: Returns TRUE for “1″, “true”, “on” and “yes”, FALSE for “0″, “false”, “off”, “no”, and “”, NULL otherwise. So if you try with ?isgoodapi=konijn you would expect NULL but that isn’t the case either.

Exploring System.CodeDom

Today i wanted to experiment with System.CodeDom. This little program requests the user to input names for a namespace, class and method. It also asks the user to input the code that should go into the method body. Then it generates an assembly (test.dll) and creates a new appdomain in which the assembly is loaded… Finally it initializes an instance of the created class and calls the method…

static void Main(string[] args)
{
 string loopEnd = "";
 while (loopEnd != "X")
 {
  //string namespaceName = "MySpace";
  //string className = "MyClass";
  //string methodName = "MyMethod";
  //StringBuilder stringBuilder = new StringBuilder("System.Console.WriteLine(\"hihi\");");

  Console.Write("Enter namespace: ");
  string namespaceName = Console.ReadLine();
  Console.Write("Enter class: ");
  string className = Console.ReadLine();
  Console.Write("Enter method: ");
  string methodName = Console.ReadLine();

  StringBuilder stringBuilder = new StringBuilder();
  Console.WriteLine("Enter method body (X to stop)");
  string input = Console.ReadLine();
  while (input != "X")
  {
   stringBuilder.Append(input);
   input = Console.ReadLine();
  }

  CodeCompileUnit codeCompileUnit = new CodeCompileUnit();

  CodeAttributeDeclaration assemblyTitleAttribute = new CodeAttributeDeclaration("System.Reflection.AssemblyTitle");
  assemblyTitleAttribute.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression("A Generated Assembly")));
  codeCompileUnit.AssemblyCustomAttributes.Add(assemblyTitleAttribute);

  CodeTypeDeclaration codeTypeDeclaration = new CodeTypeDeclaration();
  codeTypeDeclaration.Name = className;
  codeTypeDeclaration.IsClass = true;
  codeTypeDeclaration.Attributes = MemberAttributes.Public;

  CodeMemberMethod codeMemberMethod = new CodeMemberMethod();
  codeMemberMethod.Name = methodName;
  codeMemberMethod.Attributes = MemberAttributes.Public;
  codeMemberMethod.ReturnType = new CodeTypeReference(typeof(void));
  codeMemberMethod.Statements.Add(new CodeSnippetStatement(stringBuilder.ToString()));

  codeTypeDeclaration.Members.Add(codeMemberMethod);

  CodeNamespace codeNamespace = new CodeNamespace(namespaceName);
  codeNamespace.Types.Add(codeTypeDeclaration);
  codeCompileUnit.Namespaces.Add(codeNamespace);

  CompilerParameters compilerParameters = new CompilerParameters();
  compilerParameters.OutputAssembly = "test.dll";
  compilerParameters.GenerateExecutable = false;
  compilerParameters.GenerateInMemory = false;

  CSharpCodeProvider cSharpCodeProvider = new CSharpCodeProvider();
  CompilerResults compilerResults = cSharpCodeProvider.CompileAssemblyFromDom(compilerParameters, codeCompileUnit);

  AppDomain appDomain = AppDomain.CreateDomain("new appdomain");
  Assembly assembly = appDomain.Load(compilerResults.CompiledAssembly.FullName);
  object instance = assembly.CreateInstance(namespaceName + "." + className);
  instance.GetType().InvokeMember(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, instance, null);
  AppDomain.Unload(appDomain);

  Console.WriteLine("Enter X to end (enter something different to continue)");
  loopEnd = Console.ReadLine();
 }
}

Drag and Drop Microsoft Office Outlook Contacts on your WinForm

Earlier today i saw someone that wanted to know how to drag and drop Microsoft Office Outlook Contacts on his winform (and get the data of the contact). Here are the few lines of code that do what he asked for:

// in the constructor of the form (or in the InitializeComponent method if you set it via the Designer)
this.AllowDrop = true;

// handle the DragOver event
private void Form1_DragOver(object sender, DragEventArgs e)
{
 e.Effect = DragDropEffects.All;
}

// handle the DragDrop event
private void Form1_DragDrop(object sender, DragEventArgs e)
{
 string text = (string)e.Data.GetData("Text", true);
 this.label1.Text = text;

 // for more finegrained access to the data
 //string[] lines = text.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
}



screenshot of outlook contact that was dragged and dropped on the form

Looking up the MediaType of a given Logical Drive

Earlier today i saw someone asking how he could find out the MediaType of a given logical drive. The easy solution would be to iterate over DriveInfo.GetDrives and pick the one you are looking for… Anyway, i thought it would be nice to experiment with WMI so i wrote a little function that uses Win32_LogicalDisk to look the MediaType up:

static void Main(string[] args)
{
 char[] driveLetters = new char[] { 'a', 'c', 'd', 'e' };
 foreach (char driveLetter in driveLetters)
 {
  try
  {
   Console.WriteLine("Drive {0} is a {1}", driveLetter, GetMediaType(driveLetter));
  }
  catch (ManagementException)
  {
   Console.WriteLine("Drive {0} was not found", driveLetter);
  }
 }

 Console.WriteLine("Press any key to continue...");
 Console.ReadKey();
}

static string GetMediaType(char driveLetter)
{
 ManagementObject disk = new ManagementObject("win32_logicaldisk.deviceid=\"" + driveLetter + ":\"");
 disk.Get();
 return GetMediaMeaning((uint)disk["MediaType"]);
}

static string GetMediaMeaning(uint mediaType)
{
 Dictionary<uint, string> mediaTypes = new Dictionary<uint, string>();
 mediaTypes.Add(0, "Unknown Format");
 mediaTypes.Add(1, "51/4-Inch Floppy Disk - 1.2Mb - 512bytes/sector");
 mediaTypes.Add(2, "31/2-Inch Floppy Disk - 1.44Mb -512bytes/sector");
 mediaTypes.Add(3, "31/2-Inch Floppy Disk - 2.88Mb - 512bytes/sector");
 mediaTypes.Add(4, "31/2-Inch Floppy Disk - 20.8Mb - 512bytes/sector");
 mediaTypes.Add(5, "31/2-Inch Floppy Disk - 720Kb - 512bytes/sector");
 mediaTypes.Add(6, "51/4-Inch Floppy Disk - 360Kb - 512bytes/sector");
 mediaTypes.Add(7, "51/4-Inch Floppy Disk - 320Kb - 512bytes/sector");
 mediaTypes.Add(8, "51/4-Inch Floppy Disk - 320Kb - 1024bytes/sector");
 mediaTypes.Add(9, "51/4-Inch Floppy Disk - 180Kb - 512bytes/sector");
 mediaTypes.Add(10, "51/4-Inch Floppy Disk - 160Kb - 512bytes/sector");
 mediaTypes.Add(11, "Removable media other than floppy");
 mediaTypes.Add(12, "Fixed hard disk media");
 mediaTypes.Add(13, "31/2-Inch Floppy Disk - 120Mb - 512bytes/sector");
 mediaTypes.Add(14, "31/2-Inch Floppy Disk - 640Kb - 512bytes/sector");
 mediaTypes.Add(15, "51/4-Inch Floppy Disk - 640Kb - 512bytes/sector");
 mediaTypes.Add(16, "51/4-Inch Floppy Disk - 720Kb - 512bytes/sector");
 mediaTypes.Add(17, "31/2-Inch Floppy Disk - 1.2Mb - 512bytes/sector");
 mediaTypes.Add(18, "31/2-Inch Floppy Disk - 1.23Mb - 1024bytes/sector");
 mediaTypes.Add(19, "51/4-Inch Floppy Disk - 1.23Mb - 1024bytes/sector");
 mediaTypes.Add(20, "31/2-Inch Floppy Disk - 128Mb - 512bytes/sector");
 mediaTypes.Add(21, "31/2-Inch Floppy Disk - 230Mb - 512bytes/sector");
 mediaTypes.Add(22, "8-Inch Floppy Disk - 256Kb - 128bytes/sector");

 string meaning = "Unknown format";
 mediaTypes.TryGetValue(mediaType, out meaning);
 return meaning;
}

A DateAndTimePicker control

The DateTimePicker control allows the user to input a Date or a Time. The problem is that you can’t let the user pick both a date and a time with one instance of the control (unless you set the CustomFormat property and give up the ‘nice’ ui) so i decided to build my own DateAndTimePicker control:

screenshot of the dateandtimepicker control

Feel free to download and extended the DateAndTimePicker.zip.

Simple OutlookBar Control

Earlier this evening i wanted to experiment with the ToolStrip class so i decided to design a simple OutlookBar Control and a demo application that uses this control. Feel free to download OutlookBar.zip.

screenshot of OutlookBar demo

Pondering about the difference between abstract classes and interfaces

Back in May i was asked to explain the difference between an interface and an abstract class at a job interview. Obviously the interviewer wanted me to tell him that an abstract class allows you to provide a partial implementation… I answered that the major difference is the fact that with interface-based programming you’re not forced into an inheritance tree that might not make sense and that i didn’t see much use for abstract classes (I’m not sure he saw that one coming :P ). For some unknown reason this kept spinning in my head… Here’s an example of an abstract class and a concrete implementation:

abstract class FooAbstract
{
 public void DoX()
 {
  DoY();
 }

 protected abstract void DoY();
}

class FooConcrete : FooAbstract
{
 protected override void DoY()
 {
  Console.WriteLine("FooConcrete does Y");
 }
}

I find the interface-based implementation below a lot cleaner because it still provides the partial implementation but a concrete implementation is not forced into the inheritance relationship anymore. Another advantage is that the implementation only depends on the interface (the unimplemented parts) so you get some looser coupling than with abstract classes. A disadvantage is that an interface requires you to make all the unimplemented methods public:

class Foo
{
 private IAbstract myAbstract;

 public Foo(IAbstract myAbstract)
 {
  if (myAbstract == null)
  {
   throw new ArgumentNullException();
  }

  this.myAbstract = myAbstract;
 }

 public void DoX()
 {
  this.myAbstract.DoY();
 }
}

interface IAbstract
{
 void DoY();
}

class Concrete : IAbstract
{
 public void DoY()
 {
  Console.WriteLine("Concrete does Y");
 }
}

Conclusion: I still don’t see much use for abstract classes.

Helper methods for DateTime

Here are a couple of methods that help you with the manipulation of DateTime structs:

What goes up must come down…

What goes up must come down… So you might think that after each CellMouseDown event you recieve a CellMouseUp event… Well, here is some code that proves that isn’t always true:

public partial class Form1 : Form
{
 private string lastEvent;

 public Form1()
 {
  InitializeComponent();
  this.dataGridView1.ColumnCount = 10;
  this.dataGridView1.RowCount = 10;
 }

 public string LastEvent
 {
  get { return this.lastEvent; }
  set {
   if (this.lastEvent == value)
   {
    MessageBox.Show("i've detected two " + value + " after each other");
   }
   this.lastEvent = value;
  }
 }

 private void dataGridView1_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
 {
  LastEvent = "MouseDown";
 }

 private void dataGridView1_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e)
 {
  LastEvent = "MouseUp";
 }
}

And with a bit of a twisted optical mouse it’s pretty easy to see the following MessageBox

MessageBox that says the MouseDownEvent was captured two times after each other

After a bit of research i also found the following at MouseEventArgs:

It is possible to receive a MouseDown event without a corresponding MouseUp, if the user switches focus to another application before releasing the mouse button.