Introduction
I could not find a single article that got me a proper splash screen using WinForms, with true transparency, using gradient alpha colors, which could actually be dragged around, and also allows designing it using the Winforms Designer. After experimenting and combining articles, I created a solution with near perfect results.
Background
You cannot use an alpha channel image as a background image in winforms, you can only substitute a color to be treated as transparent. This does not allow gradient transparency.
Using the Code
The solution was to have a second form which takes care of the background image rendering. That second form has logic to mimic the movements of the primary form containing the controls, and which is editable using the winforms designer.
You start out adding an image with transparency to your project's resources. Use png for the best results. In my demo, I've named it Splash.png.
The primary form with all the controls is set to have a transparent background color, using the Form
's property: TransparencyKey
.
this.BackgroundImage = global::Splash.Properties.Resources.Splash;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.BackColor = System.Drawing.Color.Gold;
this.TransparencyKey = System.Drawing.Color.Gold;
Making the form draggable when clicking anywhere on the background can be done using this code snippet.
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == ApiHelper.WM_NCHITTEST && (int)m.Result == ApiHelper.HTCLIENT)
{
m.Result = new IntPtr(ApiHelper.HTCAPTION);
}
}
To initialize the background form, you should construct it in the constructor of the primary form. Make sure you clear your primary form's background image, or you'll get weird graphical artefacts!
public frmSplash()
{
InitializeComponent();
this.BackgroundImage = null;
_background = new frmBackground(Resources.Splash, this);
}
The only downside of this is that you have to set the background image of the form, as well as at the constructor code. If you change the image to have a different name, you have to change this at both places. If you don't set the background image of your primary form, you can't see what it looks like in the Designer, and it becomes hard to position the controls:
The primary form code looks like this:
using System;
using System.Drawing;
using System.Windows.Forms;
using Splash.Properties;
namespace Splash
{
public partial class frmSplash : Form
{
private frmBackground _background;
public frmSplash()
{
InitializeComponent();
this.BackgroundImage = null;
_background = new frmBackground(Resources.Splash, this);
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == ApiHelper.WM_NCHITTEST && (int)m.Result == ApiHelper.HTCLIENT)
{
m.Result = new IntPtr(ApiHelper.HTCAPTION);
}
}
private void button1_Click(object sender, EventArgs e)
{
Close();
}
}
}
The background form sets the image with alpha transparency into some graphical layer, for which I found the code here: https://blogs.msdn.microsoft.com/llobo/2006/02/07/creating-non-rectangular-splash-screen-using-alpha-channel/. The rest of the code is to mimic the movements of the first form, and making sure the z-position of the background form is always 2nd in line, using form.BringToFront()
for both forms.
The end result looks perfect, and behaves like any other form, so can be dragged around, etc.