Showing images on XP-styled buttons.

The other day, I decided to enable visual styles on one of my winform apps and found out that doing so breaks buttons with images. To get around this, I had to write a control which would inherit from the System.Windows.Forms.Button class and then handle the WM_PAINT message and draw the image myself. Below is the code I used.

/*
* Showing images on XP-styled buttons.
*
* Author: Andrew Ma
 * https://blogs.msdn.com/ajma/archive/2005/01/21/358356.aspx
 *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* This posting is provided "AS IS" with no warranties, and confers no rights.
* Use of included code samples are subject to the terms specified at https://www.microsoft.com/info/cpyright.htm
 */

using System;
using System.Drawing;
using System.Windows.Forms;

namespace ajma
{
/// <summary>
/// Represents a Windows button control that will use Visual Styles by default. This button will also draw images if specified.
/// </summary>
public class Button : System.Windows.Forms.Button
{
/// <summary>
/// WM_PAINT message
/// </summary>
const int WM_PAINT = 0xF;

  /// <summary>
/// Initializes a new instance of the Button class.
/// </summary>
public Button()
{
FlatStyle = FlatStyle.System;
}

  /// <summary>
/// Overridden. See <see cref="Control.WndProc"/>.
/// </summary>
/// <param name="m">The Windows <see cref="Message"/> to process. </param>
protected override void WndProc(ref Message m)
{
// let base.WndProc go first
base.WndProc (ref m);

   // if paiting (and there is a message), draw image on top of button
if(m.Msg == WM_PAINT && this.Image != null)
{
Graphics g = Graphics.FromHwnd(this.Handle);
switch(this.ImageAlign)
{
case ContentAlignment.BottomCenter:
g.DrawImage(this.Image, centerX(), bottom());
break;
case ContentAlignment.BottomLeft:
g.DrawImage(this.Image, left(), bottom());
break;
case ContentAlignment.BottomRight:
g.DrawImage(this.Image, right(), bottom());
break;
case ContentAlignment.MiddleCenter:
g.DrawImage(this.Image, centerX(), centerY());
break;
case ContentAlignment.MiddleLeft:
g.DrawImage(this.Image, left(), centerY());
break;
case ContentAlignment.MiddleRight:
g.DrawImage(this.Image, right(), centerY());
break;
case ContentAlignment.TopCenter:
g.DrawImage(this.Image, centerX(), top());
break;
case ContentAlignment.TopLeft:
g.DrawImage(this.Image, left(), top());
break;
case ContentAlignment.TopRight:
g.DrawImage(this.Image, right(), top());
break;
}
g.Dispose();
}
}

  #region Returns the X/Y points for the image to be drawn
private int centerX()
{
return (this.Width - this.Image.Width) / 2;
}

  private int centerY()
{
return (this.Height - this.Image.Height) / 2;
}

  private int top()
{
return 4;
}

  private int left()
{
return 4;
}

  private int right()
{
return this.Width - this.Image.Width - left();
}

  private int bottom()
{
return this.Height - this.Image.Width - top();
}
#endregion
}
}

This posting is provided "AS IS" with no warranties, and confers no rights.