Basics

My preference is to create forms entirely in code, so when I add a new file I select "class" instead of "form" to get a simple *.cs file.

Setup

Set project icon file through Properties > Application.

Start with a Windows Form application with output type Windows Application.

Add a Setup-type project to the solution.
...configuration details I didn't write down...
1) Property AddRemoveProgramsIcon: set icon like the Shortcut instructions below
2) Property Author: informational
3) Property Manufacturer: program will be installed in this folder - no spaces
4) Property ProductName:
5) Property Title:
6) Property Version: set to version number

To make the installation also add a desktop-shortcut to your program:
1a) Right-click on the Setup project in Visual Studio
1b) Select View > File System
2a) Select Application Folder folder
2b) Right-click on Primary Output From <your program>
2c) Select Create Shortcut To Primary Output From <your program>
3a) Drag the Shortcut to the User's Desktop folder
4a) Click on the Shortcut to see its Properties
4b) Select the Icon Property > Browse > Browse
4c) Change Files Of Type to .exe
4d) Click on Application Folder > Click on Primary Output From <your program> > Ok
4e) The current icon should be selected already > Click Ok
5a) Back in the File System window, right-click on the Shortcut > Select Rename
5b) Rename the Shortcut to just the display name of your program
Form

Basic code for a form:

using System;
using System.Windows.Forms;

namespace MyNamespace
{
    static class MyProgram
    {
        [STAThread]
        static void Main()
        {
            Application.Run(new MyForm());
        }
    }

    public class MyForm : Form
    {
        public MyForm()
        {
            this.Text = "My Program";
            this.Width = 800;
            this.Height = 600;
        }
    }
}

Form.ClientSize: The size of the client area of the form is the size of the form excluding the borders and the title bar. The client area of a form is the area within a form where controls can be placed.

Toggle minimize and maximize options off with booleans:
Form.MinimizeBox
Form.MaximizeBox

Hide minimize, maximize, and close buttons:

myForm.ControlBox = false;
If you don't want to hide all the buttons, you'll need to catch the FormClosing event instead and do something there.

Hide just minimize or maximize buttons:

myForm.MinimizeBox = false;
myForm.MaximizeBox = false;
Menu

Building the menu bar:

private void InitMenus()
{
    MenuItem fileMenu = new MenuItem("File");
    fileMenu.MenuItems.Add("Open", new EventHandler(OpenFile));

    this.Menu = new MainMenu();
    this.Menu.MenuItems.Add(fileMenu);
}

private void OpenFile(object sender, EventArgs e)
{
}

Add context menu (right-click menu) to any control:

ContextMenu contextMenu = new ContextMenu();
contextMenu.MenuItems.Add("Delete", OnDelete);

myControl.ContextMenu = contextMenu;

private void OnDelete(object sender, EventArgs e)
{
    Control myControl = (sender as MenuItem).GetContextMenu().SourceControl;
}
Nothing else is required to enable the context menu.
You can associate the same context menu with many different controls.
Icons

(If just using icons within an application, you can load your own or use the SystemIcons enum)

You will need to set the icon file for each Form you want it displayed on. Do not do it this way:

myForm.Icon = new Icon("icon.ico");
Even if the icon file has has property Build Action set to Embedded Resource, the installed executable will not be able to find the file.

Instead:
1) Open project properties > Application tab
2) Select "Icon and Manifest" option
3) Select your *.ico icon file
- the file will be automatically copied to the project's root folder
4) Open the properties for the icon file located in the project's root folder
5) Set "Build Action" as "Embedded Resource"
6) Set "Copy to Output Directory" to "Copy if Newer" or "Always Copy"

To use the icon:

using System.IO;
using System.Reflection;

Assembly myAssembly = Assembly.GetAssembly(typeof(anyTypeInAssembly));
Stream iconStream = myAssembly.GetManifestResourceStream("MyFullNamespace.iconFilename.ico");
this.Icon = new Icon(iconStream);
Fonts

Setting a Label and a TextBox to the same font can result in different looking fonts.
1) Label seems to round floating point font sizes up to a whole number, while TextBox seems to round them down.
2) Even with whole-number font sizes, I'm struggling with obvious differences in the rendered text. Labels are displaying at 4 points larger than expected.

Measuring expected text size with Graphics vs TextRenderer can give drastically different results.

using(Graphics graphics = this.CreateGraphics())
{
    SizeF size = graphics.MeasureString(text, font);
}
//versus
Size size = TextRenderer.MeasureText(text, font);
TextRenderer uses GDI, but Graphics uses GDI+. So if the text will be drawn with Graphics.DrawString, use the Graphics measurement. If it will be drawn with TextRenderer.DrawText then use the TextRenderer measure.

Now, Label control property UseCompatibleTextRendering defaults to False.
If True, the Label will use Graphics to draw text.
If False, the Label will use TextRenderer to draw text.
TextArea is definitely using Graphics to render text (tested), so setting the Label property to True should make the Label and TextArea render the same Font the same way.
However, neither property value fixes the problem with Labels displaying Font larger than TextArea does.

Bitmap


using System.Drawing;
...
Bitmap bitmap = new Bitmap(width, height);

Pixelated

To display a Bitmap in pixelated form instead of anti-aliased:

protected override void OnPaint(PaintEventArgs paintEventArgs)
{
    paintEventArgs.Graphics.SmoothingMode = SmoothingMode.None; //allow pixelation
    paintEventArgs.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor; //stop color smoothing
    paintEventArgs.Graphics.PixelOffsetMode = PixelOffsetMode.Half; //stops image from being shifted up-left by a half-pixel
    base.OnPaint(paintEventArgs);
}

Region Locked

I've had trouble getting "region is already locked" errors from multi-threaded bitmaps when I rely on Clone to make an independent copy of a bitmap.

Bitmap copy = (Bitmap)original.Clone();
I don't have that trouble when I use new Bitmap to make the copy.

Bitmap copy = new Bitmap(original);
I can't find documentation about this, but recommend the second method for copying bitmaps.

Exception: A generic error occurred in GDI+
When: saving an image that was opened from file
The problem is that GDI+ expects the original MemoryStream to remain open for the full life of the Image. Here's how to load an image file without this requirement.

private Bitmap SafeLoadImage(string fullFilename)
{
    byte[] imageBytes = File.ReadAllBytes(fullFilename);
    using(MemoryStream stream = new MemoryStream(imageBytes))
    {
        using(Image image = Image.FromStream(stream, false, true))
        {
            return new Bitmap(image);
        }
    }
}

Controls

Anchor Vs Dock

"Anchor" refers to the position a control has relative to the edges of the form. A textbox, for example, that is anchored to the left edge of a form will stay in the same position as the form is resized.

Anchoring a control to its parent control ensures that the anchored edges remain in the same position relative to the edges of the parent control when the parent control is resized.

"Docking" refers to how much space you want the control to take up on the form. If you dock a control to the left of the form, it will stretch itself to the height of the form, but its width will stay the same.

The Anchor and Dock properties are mutually exclusive. Only one can be set at a time, and the last one set takes precedence.

AnchorStyles: None, Top, Bottom, Left, Right

Control.Anchor = AnchorStyles.Top | AnchorStyles.Left;

DockStyle: None, Top, Bottom, Left, Right, Fill

Control.Dock = DockStyle.Fill;

Properties

Basic properties:

Control.BackColor = Color.Red;
Control.Cursor = Cursors.Hand;
Control.BackgroundImage = Image.FromFile(filename);
Control.BackgroundImageLayout = ImageLayout.Stretch;

Scrolling

If you set Control.AutoScroll=true, you can still manually set the scroll position with Control.AutoScrollPosition. Set it to a Point such that (0,0) is the top-left corner.

Transparent Controls

WinForms supports controls with transparent background such that the parent control will fill in the missing space.
That means controls can only be transparent is regards to their parent, not in regards to other controls they overlap.

Note: buttons cannot have transparent backgrounds this way.


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

public class MyControl : UserControl
{
    public MyControl()
    {
        SetStyle(ControlStyles.SupportsTransparentBackColor, true);
        SetStyle(ControlStyles.Opaque, true);
        this.BackColor = Color.Transparent;
    }
}

Alternative is to set the Control.Region to only contain non-transparent parts of the control. Note that areas outside of Region will not react to user interaction.

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

public class RoundedCorners : UserControl
{
    private int radius = 20;

    protected override void OnSizeChanged(EventArgs e)
    {
        base.OnSizeChanged(e);
        this.RecreateRegion();
    }

    private void RecreateRegion()
    {
        Rectangle bounds = ClientRectangle;
        regionPath = GetRoundedRectangle(bounds, this.Radius);
        this.Region = new Region(regionPath);
        this.Invalidate();
    }

    private GraphicsPath GetRoundedRectangle(Rectangle bounds, int radius)
    {
        GraphicsPath path = new GraphicsPath();
        path.AddArc(bounds.X, bounds.Y, radius, radius, 180, 90);
        path.AddArc(bounds.X + bounds.Width - radius, bounds.Y, radius, radius, 270, 90);
        path.AddArc(bounds.X + bounds.Width - radius, bounds.Y + bounds.Height - radius,
                    radius, radius, 0, 90);
        path.AddArc(bounds.X, bounds.Y + bounds.Height - radius, radius, radius, 90, 90);
        path.CloseAllFigures();
        return path;
    }
}

Note: When building a Control.Region, all coordinates are relative to the top-left corner of the control being (0,0).

Note: Region.Union(Region) does not work if one of the Regions is empty. And trying to set Control.Region to an empty Region is ignored.

Text Box

booleans:
TextBox.Multiline
TextBox.WordWrap
TextBox.AcceptsReturn
TextBox.AcceptsTabs

TextBox.Text = text displayed in the text box. Used "\r\n" for line break.
TextBox.Lines = array of lines in the text box
TextBox.ReadOnly = boolean for whether text is editable or not
TextBox.ScrollBars = ScrollBars.Vertical or Horizontal or Both

Accurately count number of lines displayed in a text box when line-wrapping is enabled.
GetFirstCharIndexFromLine(lineIndex) returns the characterIndex (where 0 is the first char in the textbox) that begins the indicated line, taking line-wrap into account.
lineIndex starts at 0.

private int CountLines(RichTextBox textBox)
{
    int lineCount = 1;
    while(textBox.GetFirstCharIndexFromLine(lineCount) > -1)
    {
        lineCount++;
    }
    return lineCount;
}
Dialog

Open File Dialog:

OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "Image Files|*.BMP;*.PNG;*.JPG;*.JPEG";
openFileDialog.Title = "Select an Image File";

if(openFileDialog.ShowDialog() != System.Windows.Forms.DialogResult.OK)
{
    return;
}

The "Filter" property accepts a string in format:
"text description of type|semi-colon delimited list of *.TYPE|next text description|next list of *.TYPES"

Full list of DialogResults:
OK, Cancel, Abort, Retry, Ignore, Yes, No

The "OpenFileDialog.FileName" property is a string of the full path to the file.

Use case: dialog opens > user selects an option > an operation is run and it fails
How to cancel the "end dialog" event triggered by the user selecting an option with a DialogResult defined?


//this will keep your dialog open
this.DialogResult = DialogResult.None;

Center a dialog in the owner form:

//in owner
using(MyDialog form = new MyDialog())
{
    form.ShowDialog(this); //"this" sets the current form as the owner
}
//in dialog
public MyDialog()
{
    this.Shown += new EventHandler(Form_OnShown);
}
private void Form_OnShown(object sender, EventArgs e)
{
    Control owner = this.Owner;
    if(owner != null)
    {
        this.StartPosition = FormStartPosition.Manual;
        this.Location = new Point(owner.Location.X + (owner.Width - this.Width) / 2, owner.Location.Y + (owner.Height - this.Height) / 2);
    }
}
Message Box

Display a pop-up message to the user:

DialogResult result = MessageBox.Show("user message", "Title", MessageBoxButtons.OK, MessageBoxIcon.Error);

MessageBoxButtons: OK, OKCancel, AbortRetryIgnore, YesNoCancel, YesNo, RetryCancel

To create a custom message box or dialog, create a normal form and display it with ShowDialog(). This will display the form modally (as a modal form), meaning nothing except this form will accept input until the form is closed.

public class MyModal : Form
{
    public MyModal()
    {
        //create form
    }
    private void CloseForm()
    {
        this.DialogResult = DialogResult.OK;
        this.Close();
    }
}

public class MainForm : Form
{
    public MainForm()
    {
        //create form
    }
    public void DisplayModalForm()
    {
        using(MyModal myModal = new MyModal())
        {
            DialogResult result = myModal.ShowDialog();
        }
    }
}

To set the location of the dialog form:

using(MyModal form = new MyModal())
{
    form.StartPosition = FormStartPosition.Manual;
    form.Location = new Point(this.Location.X + 30, this.Location.Y + 30); //point on screen
    form.ShowDialog();
}
Picture Box

Display an image.

PictureBox pictureBox = new PictureBox();
pictureBox.Image = myBitmap; //load image from program memory
//or
pictureBox.ImageLocation = "myImage.png"; //load image from disk

PictureBox.SizeMode
- Normal: image will remain at actual size in top-left corner of control
- StretchImage: image will stretch in both dimensions to perfectly fill control
- AutoSize: looks same as Normal
- CenterImage: image will remain at actual size, with center of image always at center of control
- Zoom: image will stretch (maintaining original ratio) to fit control

PictureBox that will show image pixelated when zoomed in:

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

namespace PerpetualPaint
{
    public class PixelPictureBox : PictureBox
    {
        protected override void OnPaint(PaintEventArgs paintEventArgs)
        {
            if(ZoomedIn(paintEventArgs.Graphics))
            {
                paintEventArgs.Graphics.SmoothingMode = SmoothingMode.None; //allow pixelation
                paintEventArgs.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor; //stop color smoothing
                paintEventArgs.Graphics.PixelOffsetMode = PixelOffsetMode.Half; //stops image from being shifted up-left by a half-pixel
            }
            base.OnPaint(paintEventArgs);
        }

        private bool ZoomedIn(Graphics graphics)
        {
            if(this.Image == null)
                return false;
            return (this.Image.Width < graphics.ClipBounds.Width || this.Image.Height < graphics.ClipBounds.Height);
        }
    }
}

Mouse

Getting click point on screen:

public void OnClick(object sender, EventArgs e)
{
    Point screenPoint = new Point(MousePosition.X, MousePosition.Y);
}

Getting click point in control:

public void OnClick(object sender, EventArgs e)
{
    Point screenPoint = new Point(MousePosition.X, MousePosition.Y);
    Point controlPoint = control.PointToClient(screenPoint);
}
Graphics

If you need to use a Graphics object, like for measuring text size, but none is available:

using(Graphics graphics = Graphics.FromHwnd(IntPtr.Zero))
{
}