Changing the Form Default BackColor at Runtime

C

Collin

I have a program that have over 10 forms in it. The BackColor for each form
defaults to System.Drawing.SystemColors.Control.

How can I override or change what that color is? Basically what I would
like to do is have different color schemes available to the user without
having to program each and forms/controls in the application.

How can I build a new color pallete that will override the SystemColors
without affecting the base OS color scheme.

Thank you.
 
M

Morten Wennevik [C# MVP]

Hi Collin,

I'm afraid you will have to do a bit of coding to get this to work. Some
third party control collection support a CSS style file for handling
application wide looks, but this is not provided in the standard .Net
Framework library.

However, the principles are easy enough. You will need a class that holds
all the colors used in your application. This class can be tied to a
settings file if you wish to save the user preferences as well. All your
controls need to bind their Color properties against a BindingSource of this
class.

// Form1 code

ColorSettings colorSettings = new ColorSettings();
BindingSource bs;

protected override void OnLoad(EventArgs e)
{
bs = new BindingSource(colorSettings, "");
BindColors(bs);
}
// Change this method to suit your needs
private void BindColors(BindingSource source)
{
this.DataBindings.Add("BackColor", source, this.GetType().Name);
foreach (Control c in this.Controls)
{
if (c is TextBox || c is DataGridView)
continue;
string type = c.GetType().Name;
c.DataBindings.Add("BackColor", source, type);
}
}

// ColorSettings class

class ColorSettings : INotifyPropertyChanged
{
private Color _Form1 = SystemColors.Control;

public Color Form1
{
get { return _Form1; }
set { _Form1 = value; NotifyPropertyChanged("Form1"); }
}

private Color _Button = SystemColors.Control;

public Color Button
{
get { return _Button; }
set { _Button = value; NotifyPropertyChanged("Button"); }
}

public event PropertyChangedEventHandler PropertyChanged;

private void NotifyPropertyChanged(string property)
{
if (PropertyChanged != null)
PropertyChanged(null, new PropertyChangedEventArgs(property));
}

// Button event

private void button1_Click(object sender, EventArgs e)
{
colorSettings.Form1 = Color.Red;
colorSettings.Button = Color.Blue;
}

All controls bound to the properties Form1 and Button will have their
BackColor updated.
 
C

Collin

Morten, I had a feeling I would have to write a lot of code. Thanks for
pointing me in the direction of using the BindingSource. I will have to
research the INotifyPropertyChanged interface.

I have another question, but I think I already know the answer. Here goes
anyway.
How do I handle controls that use the following colors:
SystemColors.Control
SystemColors.ControlDark
SystemColors.ControlDarkDark
SystemColors.ControlLight, etc.



Morten Wennevik said:
Hi Collin,

I'm afraid you will have to do a bit of coding to get this to work. Some
third party control collection support a CSS style file for handling
application wide looks, but this is not provided in the standard .Net
Framework library.

However, the principles are easy enough. You will need a class that holds
all the colors used in your application. This class can be tied to a
settings file if you wish to save the user preferences as well. All your
controls need to bind their Color properties against a BindingSource of this
class.

// Form1 code

ColorSettings colorSettings = new ColorSettings();
BindingSource bs;

protected override void OnLoad(EventArgs e)
{
bs = new BindingSource(colorSettings, "");
BindColors(bs);
}
// Change this method to suit your needs
private void BindColors(BindingSource source)
{
this.DataBindings.Add("BackColor", source, this.GetType().Name);
foreach (Control c in this.Controls)
{
if (c is TextBox || c is DataGridView)
continue;
string type = c.GetType().Name;
c.DataBindings.Add("BackColor", source, type);
}
}

// ColorSettings class

class ColorSettings : INotifyPropertyChanged
{
private Color _Form1 = SystemColors.Control;

public Color Form1
{
get { return _Form1; }
set { _Form1 = value; NotifyPropertyChanged("Form1"); }
}

private Color _Button = SystemColors.Control;

public Color Button
{
get { return _Button; }
set { _Button = value; NotifyPropertyChanged("Button"); }
}

public event PropertyChangedEventHandler PropertyChanged;

private void NotifyPropertyChanged(string property)
{
if (PropertyChanged != null)
PropertyChanged(null, new PropertyChangedEventArgs(property));
}

// Button event

private void button1_Click(object sender, EventArgs e)
{
colorSettings.Form1 = Color.Red;
colorSettings.Button = Color.Blue;
}

All controls bound to the properties Form1 and Button will have their
BackColor updated.

--
Happy Coding!
Morten Wennevik [C# MVP]


Collin said:
I have a program that have over 10 forms in it. The BackColor for each form
defaults to System.Drawing.SystemColors.Control.

How can I override or change what that color is? Basically what I would
like to do is have different color schemes available to the user without
having to program each and forms/controls in the application.

How can I build a new color pallete that will override the SystemColors
without affecting the base OS color scheme.

Thank you.
 
M

Morten Wennevik [C# MVP]

Collin said:
Morten, I had a feeling I would have to write a lot of code. Thanks for
pointing me in the direction of using the BindingSource. I will have to
research the INotifyPropertyChanged interface.

I have another question, but I think I already know the answer. Here goes
anyway.
How do I handle controls that use the following colors:
SystemColors.Control
SystemColors.ControlDark
SystemColors.ControlDarkDark
SystemColors.ControlLight, etc.

Same principle. Instead of having a separate color for various controls you
could also databind all controls set to use SystemColors Control to the same
color property like ColorSettings.DarkControl. Same goes for any other
property as well.

The INotifyPropertyChanged interface is supported by controls. It lets you
notify the controls at runtime that they should reread their databindings.
If you don't use it, you will find that properties changed programmatically
will not update on screen until you do something that causes the control to
refresh their databindings.

Using a BindingSource you can also force a BindingSource.ResetBindings() if
you find that changes aren't immediatly reflected on screen.
 
C

Collin

Morten, I just implemented your suggestion. Ii works great for the stuff I
can change. But, how do I control the scrollbars and the edges/borders of
the textboxes or comboxes?
 
M

Morten Wennevik [C# MVP]

Hi Collin,

Alas, some controls are not so easy to change as they are masked win32
controls, like ScrollBar and TextBox, and do drawing outside of .Net. There
are ways to overcome this, but the complexity increases many times.

Overriding WndProc you can listen for system messages, and in case of the
ScrollBar, the WM_CTLCOLORSCROLLBAR will be sent.

The code below demonstrates how you can change scrollbar color, but it will
only change part of the color.

protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch (m.Msg)
{
case (int)WindowMessages.WM_CTLCOLORSCROLLBAR:
IntPtr hdc = m.WParam;
using (Graphics g = Graphics.FromHdc(hdc))
{
g.FillRectangle(Brushes.Green, 0, 0, 100, 100);
}
break;
default:
break;
}
}

You may need to call Win32 methods directly (pinvoke) for a full change.

The border part of controls like TextBox is handled by trapping non client
paint messages (WM_NCPAINT). An example is shown in this article.

[A Padded Rich Text Box Subclass]
http://69.10.233.10/KB/edit/PaddedRichTextBox.aspx

WindowMessages is just an enum with all messages listed.

public enum WindowMessages
{
WM_NULL = 0x0000,
WM_CREATE = 0x0001,
WM_DESTROY = 0x0002,
WM_MOVE = 0x0003,
WM_SIZE = 0x0005,
WM_ACTIVATE = 0x0006,
WM_SETFOCUS = 0x0007,
WM_KILLFOCUS = 0x0008,
WM_ENABLE = 0x000A,
WM_SETREDRAW = 0x000B,
WM_SETTEXT = 0x000C,
WM_GETTEXT = 0x000D,
WM_GETTEXTLENGTH = 0x000E,
WM_PAINT = 0x000F,
WM_CLOSE = 0x0010,
WM_QUERYENDSESSION = 0x0011,
WM_QUIT = 0x0012,
WM_QUERYOPEN = 0x0013,
WM_ERASEBKGND = 0x0014,
WM_SYSCOLORCHANGE = 0x0015,
WM_ENDSESSION = 0x0016,
WM_SHOWWINDOW = 0x0018,
WM_CTLCOLOR = 0x0019,
WM_WININICHANGE = 0x001A,
WM_SETTINGCHANGE = 0x001A,
WM_DEVMODECHANGE = 0x001B,
WM_ACTIVATEAPP = 0x001C,
WM_FONTCHANGE = 0x001D,
WM_TIMECHANGE = 0x001E,
WM_CANCELMODE = 0x001F,
WM_SETCURSOR = 0x0020,
WM_MOUSEACTIVATE = 0x0021,
WM_CHILDACTIVATE = 0x0022,
WM_QUEUESYNC = 0x0023,
WM_GETMINMAXINFO = 0x0024,
WM_PAINTICON = 0x0026,
WM_ICONERASEBKGND = 0x0027,
WM_NEXTDLGCTL = 0x0028,
WM_SPOOLERSTATUS = 0x002A,
WM_DRAWITEM = 0x002B,
WM_MEASUREITEM = 0x002C,
WM_DELETEITEM = 0x002D,
WM_VKEYTOITEM = 0x002E,
WM_CHARTOITEM = 0x002F,
WM_SETFONT = 0x0030,
WM_GETFONT = 0x0031,
WM_SETHOTKEY = 0x0032,
WM_GETHOTKEY = 0x0033,
WM_QUERYDRAGICON = 0x0037,
WM_COMPAREITEM = 0x0039,
WM_GETOBJECT = 0x003D,
WM_COMPACTING = 0x0041,
WM_COMMNOTIFY = 0x0044,
WM_WINDOWPOSCHANGING = 0x0046,
WM_WINDOWPOSCHANGED = 0x0047,
WM_POWER = 0x0048,
WM_COPYDATA = 0x004A,
WM_CANCELJOURNAL = 0x004B,
WM_NOTIFY = 0x004E,
WM_INPUTLANGCHANGEREQUEST = 0x0050,
WM_INPUTLANGCHANGE = 0x0051,
WM_TCARD = 0x0052,
WM_HELP = 0x0053,
WM_USERCHANGED = 0x0054,
WM_NOTIFYFORMAT = 0x0055,
WM_CONTEXTMENU = 0x007B,
WM_STYLECHANGING = 0x007C,
WM_STYLECHANGED = 0x007D,
WM_DISPLAYCHANGE = 0x007E,
WM_GETICON = 0x007F,
WM_SETICON = 0x0080,
WM_NCCREATE = 0x0081,
WM_NCDESTROY = 0x0082,
WM_NCCALCSIZE = 0x0083,
WM_NCHITTEST = 0x0084,
WM_NCPAINT = 0x0085,
WM_NCACTIVATE = 0x0086,
WM_GETDLGCODE = 0x0087,
WM_SYNCPAINT = 0x0088,
WM_NCMOUSEMOVE = 0x00A0,
WM_NCLBUTTONDOWN = 0x00A1,
WM_NCLBUTTONUP = 0x00A2,
WM_NCLBUTTONDBLCLK = 0x00A3,
WM_NCRBUTTONDOWN = 0x00A4,
WM_NCRBUTTONUP = 0x00A5,
WM_NCRBUTTONDBLCLK = 0x00A6,
WM_NCMBUTTONDOWN = 0x00A7,
WM_NCMBUTTONUP = 0x00A8,
WM_NCMBUTTONDBLCLK = 0x00A9,
WM_KEYDOWN = 0x0100,
WM_KEYUP = 0x0101,
WM_CHAR = 0x0102,
WM_DEADCHAR = 0x0103,
WM_SYSKEYDOWN = 0x0104,
WM_SYSKEYUP = 0x0105,
WM_SYSCHAR = 0x0106,
WM_SYSDEADCHAR = 0x0107,
WM_KEYLAST = 0x0108,
WM_IME_STARTCOMPOSITION = 0x010D,
WM_IME_ENDCOMPOSITION = 0x010E,
WM_IME_COMPOSITION = 0x010F,
WM_IME_KEYLAST = 0x010F,
WM_INITDIALOG = 0x0110,
WM_COMMAND = 0x0111,
WM_SYSCOMMAND = 0x0112,
WM_TIMER = 0x0113,
WM_HSCROLL = 0x0114,
WM_VSCROLL = 0x0115,
WM_INITMENU = 0x0116,
WM_INITMENUPOPUP = 0x0117,
WM_MENUSELECT = 0x011F,
WM_MENUCHAR = 0x0120,
WM_ENTERIDLE = 0x0121,
WM_MENURBUTTONUP = 0x0122,
WM_MENUDRAG = 0x0123,
WM_MENUGETOBJECT = 0x0124,
WM_UNINITMENUPOPUP = 0x0125,
WM_MENUCOMMAND = 0x0126,
WM_CTLCOLORMSGBOX = 0x0132,
WM_CTLCOLOREDIT = 0x0133,
WM_CTLCOLORLISTBOX = 0x0134,
WM_CTLCOLORBTN = 0x0135,
WM_CTLCOLORDLG = 0x0136,
WM_CTLCOLORSCROLLBAR = 0x0137,
WM_CTLCOLORSTATIC = 0x0138,
WM_MOUSEMOVE = 0x0200,
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_LBUTTONDBLCLK = 0x0203,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205,
WM_RBUTTONDBLCLK = 0x0206,
WM_MBUTTONDOWN = 0x0207,
WM_MBUTTONUP = 0x0208,
WM_MBUTTONDBLCLK = 0x0209,
WM_MOUSEWHEEL = 0x020A,
WM_PARENTNOTIFY = 0x0210,
WM_ENTERMENULOOP = 0x0211,
WM_EXITMENULOOP = 0x0212,
WM_NEXTMENU = 0x0213,
WM_SIZING = 0x0214,
WM_CAPTURECHANGED = 0x0215,
WM_MOVING = 0x0216,
WM_DEVICECHANGE = 0x0219,
WM_MDICREATE = 0x0220,
WM_MDIDESTROY = 0x0221,
WM_MDIACTIVATE = 0x0222,
WM_MDIRESTORE = 0x0223,
WM_MDINEXT = 0x0224,
WM_MDIMAXIMIZE = 0x0225,
WM_MDITILE = 0x0226,
WM_MDICASCADE = 0x0227,
WM_MDIICONARRANGE = 0x0228,
WM_MDIGETACTIVE = 0x0229,
WM_MDISETMENU = 0x0230,
WM_ENTERSIZEMOVE = 0x0231,
WM_EXITSIZEMOVE = 0x0232,
WM_DROPFILES = 0x0233,
WM_MDIREFRESHMENU = 0x0234,
WM_IME_SETCONTEXT = 0x0281,
WM_IME_NOTIFY = 0x0282,
WM_IME_CONTROL = 0x0283,
WM_IME_COMPOSITIONFULL = 0x0284,
WM_IME_SELECT = 0x0285,
WM_IME_CHAR = 0x0286,
WM_IME_REQUEST = 0x0288,
WM_IME_KEYDOWN = 0x0290,
WM_IME_KEYUP = 0x0291,
WM_MOUSEHOVER = 0x02A1,
WM_MOUSELEAVE = 0x02A3,
WM_CUT = 0x0300,
WM_COPY = 0x0301,
WM_PASTE = 0x0302,
WM_CLEAR = 0x0303,
WM_UNDO = 0x0304,
WM_RENDERFORMAT = 0x0305,
WM_RENDERALLFORMATS = 0x0306,
WM_DESTROYCLIPBOARD = 0x0307,
WM_DRAWCLIPBOARD = 0x0308,
WM_PAINTCLIPBOARD = 0x0309,
WM_VSCROLLCLIPBOARD = 0x030A,
WM_SIZECLIPBOARD = 0x030B,
WM_ASKCBFORMATNAME = 0x030C,
WM_CHANGECBCHAIN = 0x030D,
WM_HSCROLLCLIPBOARD = 0x030E,
WM_QUERYNEWPALETTE = 0x030F,
WM_PALETTEISCHANGING = 0x0310,
WM_PALETTECHANGED = 0x0311,
WM_HOTKEY = 0x0312,
WM_PRINT = 0x0317,
WM_PRINTCLIENT = 0x0318,
WM_HANDHELDFIRST = 0x0358,
WM_HANDHELDLAST = 0x035F,
WM_AFXFIRST = 0x0360,
WM_AFXLAST = 0x037F,
WM_PENWINFIRST = 0x0380,
WM_PENWINLAST = 0x038F,
WM_APP = 0x8000,
WM_USER = 0x0400,
WM_REFLECT = WM_USER + 0x1c00
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top