static void

WinForms.Net

Scrappy notes because I'm primarily a web developer

Events

Note the order: Enter - GotFocus - TextChanged - Leave - Validating - Validated - LostFocus
TextBox can be ReadOnly (gets focus), !Enabled (no focus).
Validation levels:

Exception Handling

You should at least log all unhandled exceptions, and preferably show a MessageBox saying sorry before Application.Exit().
In Asp.Net it's simple to trap unhandled exceptions in Application_Error in global.asax or in CustomErrors in web.config.
In Winforms and console apps, you can use the AppDomain.UnhandledException event:

AppDomain.CurrentDomain.UnhandledException +=
    (o, eventArgs) =>
        {
            Console.WriteLine("Application errrored!");
            Log.LogException(eventArgs.ExceptionObject as Exception);
            Environment.Exit(0);
        };

In Winforms you also have a Application.ThreadException (check the UnhandledExceptionMode as by default you'll swallow the exception and continue). It only traps exceptions on the main UI thread, so you probably need the AppDomain event too.
You can use Application.Exit() or Environment.Exit(0) to close (and stop the default .Net unhandled exception dialog).

GDI+

Is also used with the PrintPage event of the PrintDocument component
Graphics object is available from a form1.CreateGraphics factory method (anything Control-derived), from PaintEventArgs(or PrintPageEventArgs).Graphics, or the static Graphics.FromImage(img)
Draw* for lines (with a Pen), Fill* for filled shapes (with a Brush).
Pen myPen = new Pen(myBrush)
Coordinates: Point, Size, Rectangle (a Size with a Point as origin).

g.DrawString(str, new Font("Arial", 36, FontStyle.Regular), myPen, 0, 0);
Dispose all Pens/Brushes/Graphics objects (enclose them in using)
GraphicsPaths- is for complex shapes- use AddString etc, StartFigure/CloseFigure

Making thumbnail (best quality)

private static void ResizeImage(string origPath, string smallPath)
{
    using (var orig = Image.FromFile(origPath))
    {
        const int newWidth = 150;
        const int newHeight = 200;
 
        var small = new Bitmap(newWidth, newHeight);
        using (var g = Graphics.FromImage(small))
        {
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.FillRectangle(Brushes.White, 0, 0, newWidth, newHeight);
            g.DrawImage(orig, 0, 0, newWidth, newHeight);
        }
        small.Save(smallPath, ImageFormat.Jpeg);
    }          
}

Compress a jpeg

private static void CompressImage(string origPath, string compressedPath)
{
    using (var orig = Image.FromFile(origPath))
    {
        //look up jpeg mime type
        ImageCodecInfo codec = ImageCodecInfo.GetImageEncoders().First(
            e => e.FormatID == ImageFormat.Jpeg.Guid);
        var encoderPars = new EncoderParameters();
        //quality must be a LONG from 1 to 100 - not an INT
        encoderPars.Param[0] =
            new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 60L);
        orig.Save(compressedPath, codec, encoderPars);
    }
}

Overlaying images

private static void OverlayImage(string origPath, string overlayPath, string newPath)
{
    using (Image background = Image.FromFile(origPath))
    {
        using (var g = Graphics.FromImage(background))
        {
            using (var overlay = new Bitmap(overlayPath))
            {
                g.DrawImage(overlay, new Point(780, 0));
            }
        }
        background.Save(newPath, ImageFormat.Jpeg);
    }
}

DPI problems: if the image isn't default 96dpi, bitmap.SetResolution(overlay.HorizontalResolution, overlay.VerticalResolution);

Authoring Controls

Add toolbox icons- [ToolboxBitmap(typeof(Button))]. Or pass the path, or simply put add YourClassName.bmp as an embedded resource (bmp filename== classname) and it does it magically.
You can also use LicenseManager.Validate.

Help

Settings

WinForms 2.0 designer - properties - Application Settings/ PropertyBindings creates the Settings class and binds for you. (msdn)
For C# (not VB) you need:

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    Properties.Settings.Default.Save();
}

Tooltips on TreeView treenodes

Option 1: treeview1.ShowNodeToolTips = true and set the treeNode's ToolTipText
Option 2: Add a Windows.Forms.ToolTip, and handle the treeview's MouseMove event. You can use the treeNode's ToolTipText directly, or cast the Tag. You need to remember the last node or tooltip to avoid unpleasant repeat flashing as the cursor moves.

private string lastNode; //remember tooltips to avoid flashing
private void DatabaseScripterTreeView_MouseMove(object sender, MouseEventArgs e)
{
    // Get the node at the current mouse pointer location.
    TreeNode theNode = GetNodeAt(e.X, e.Y);
 
    // if mouse not over a node, or it has no tag, no tooltip
    if (theNode == null || string.IsNullOrEmpty(theNode.ToolTipText))
    {
        toolTip1.Active = false;
        lastNode = null;
        return;
    }
 
    //check still on same node - otherwise fires repeatedly
    if (theNode.ToolTipText == lastNode) return;
    lastNode = theNode.ToolTipText;
 
    //show the tooltip
    var tag = theNode.ToolTipText;
 
    if (!toolTip1.Active) toolTip1.Active = true;
    toolTip1.SetToolTip(this, tag);
}

CrossThread Pattern

For the dreaded cross-thread exception. You can either define a delegate or use an Action/ Func (or new MethodInvoker- anonymous delegates don't work).

void Model_Changed(object sender, EventArgs e)
{
    //model changed by background worker or UI
    UpdateUI();
}
 
/// <summary>
/// Updates the UI in a threadsafe way
/// </summary>
private void UpdateUI()
{
    if (InvokeRequired)
    {
        //call myself on the windows thread
        Invoke(new Action(UpdateUI));
    }
    else
    {
        txtName.Text = "Hello";
    }
}