C# Application wide color management - c#

im on to write a large C# Application.
The point is that the colors of the controls should be adjustable by the user of the application.
It would be really nice if there are any solution to override(only for the context of this application) the System.Drawing.SystemColors, so that i do not have to set the value of every single control by hand.
Do anybody know an solution for my problem which is that simple?
Thanks

Look at Application Setting bindings. Not sure how you would do this for all controls, but simply recursing through the control tree should be sufficient.

I think your best approach would be to inherit each control and set its default display properties. This would give you a library of the standard WinForms controls that you could easily customize and re-use. More information here (in VB, I couldn't find examples in C#).

You shouldn't need to override the system defaults but you are able to define your own colours.
Color NastyColour = Color.FromArgb(1, 2, 3);
1 = Red
2 = Green
3 = Blue

Unfortunately it's not possible to modify the Windows colour scheme just for your application.
Winforms makes it possible to change things like the background colour for all controls on a form, but for many areas (such as the bevel colours on buttons, or window title bars), you'll probably need to resort to painting the control yourself.

I wrote the code below to do something like this. I'm not particularly happy with it as it needs specialized handling for any controls that are out of the ordinary, but it did the job. I keep an instance of Painter around, and call Apply every time I create a form, passing the form as the argument. It recurses through all the child controls, altering their appearance
public class Painter
{
Color foreColor;
Color backColor;
Color altBackColor;
Color buttonColor;
Font font;
public Painter(Color foreColor, Color backColor, Color altBackColor, Color buttonColor, Font font)
{
this.foreColor=foreColor;
this.backColor=backColor;
this.altBackColor=altBackColor;
this.buttonColor=buttonColor;
this.font=font;
}
public void Apply(Control c)
{
if(c==null)
return;
c.ForeColor = foreColor;
c.BackColor = (c is Button ) ? buttonColor
: backColor;
if (c is DataGridView)
{
var dgv = (DataGridView) c;
dgv.BackgroundColor = BackColor;
dgv.AlternatingRowsDefaultCellStyle.BackColor = altBackColor;
dgv.ColumnHeadersDefaultCellStyle.BackColor = buttonColor;
}
c.Font = font;
foreach(Control child in c.Controls)
Apply(child);
}
}

Spend $1000 and get a copy of DevExpress. We're writing a large application using their framework, and the skinning ability is great.
I know this doesn't sound like the best answer, but if you're looking for application wide skinning ability, a third-party library may be appropriate.

Related

Controlling how, when, and if child controls are drawn (.NET)

I am writing an application in .NET that has a plugin interface. That plugin interface provides several ways to draw information (controls) onto the surface of the application window. While there are several reasons why I am doing this, the main reason is to provide custom colorization to text, either through the use of a graphic or directly manipulating the color of the text based on the background color. I do this through the use of a "text mask" which is a black and white bitmap that works as an "alpha" map to let the Paint method know where to apply the texture/color changes.
The plugin developer has the option of using regular text (such as with a label), mask text (which is drawn to the mask rather than as a regular control), OR letting the user decide. To go along with this, I have provided a modified label class that can either be drawn "normally' (when the text mask is not set for the control), or to the text mask when the User OR Developer decides (depending on what the plugin developer wishes to offer to the user). Here is the class's code so that you understand how this is being done:
public class MaskingLabel : Label
{
private static readonly SolidBrush maskBrush = new SolidBrush(Color.White);
public Bitmap Mask { get; set; }
public MaskingLabel() : base() { }
protected override void OnPaint(PaintEventArgs e)
{
if (Mask == null)
base.OnPaint(e);
else
{
Graphics g = Graphics.FromImage(Mask);
g.DrawString(Text, Font, maskBrush, Location);
}
}
}
The problem I am running into is that this approach requires that I handle controls in a very specific order so that the form is drawn correctly. I need to find the most efficient approach to get the tasks listed below done in the order given. I have thought of three possibilities discussed further down. For reference, this is the order in which tasks must be done:
All "MaskingLabel" controls that have the bitmap object set to the mask must be drawn first so that the mask is created before the next step.
The mask is applied to the background picture.
The resulting Bitmap is drawn in a way similar to the way a background would be drawn (except that it is modified first).
The rest of the controls are drawn as normal.
Is there a way for me to insure this happens without separating the controls manually? My first guess is no. As such, I have a few guesses below about how I should go about this. I was hoping someone with more in depth knowledge of GDI+ could offer some insight.
One idea that has occurred to me is to draw the masked controls during the OnPaintBackground method. However, I don't want to waste time by painting the controls twice. This means I would need to filter out which controls are drawn during the main Paint method which effectively leads us to option 2 (FAIK):
I can manually filter out the controls which draw to the mask so that they don't get added to the control. My question here though is would they get drawn at all? Can I manually force them to invoke the OnPaint method?
If doing that wouldn't work, then perhaps I can create a separate derived panel control to serve as a "backdrop" child control that acts as the background picture which can be forced to be drawn first?
EDIT (With Part of the answer):
I realized after posting this that I already have part of the solution built into my project. Still, I think it is a legitimate question to ask, so if anyone can add insight beyond what I have done in my description below, it is welcome.
Specifically, my project has only two controls that are added to the "root" form: a bar that goes to the top (docked at the top when it is shown), and a transparent panel that occupies the rest of the space (with a dock style set to fill). So my solution would be to add the mask controls to the main form and add all the rest to the panel. This only leaves one remaining issue to be resolved: How do I make sure that the panel and the bar are drawn last? (As part of step 4 in the first list?)

How to make Custom color in c#?

In Visual Studio, please suggest how to make custom color for a control and add it to property-> backColor Section.?
You can type a comma separated RGB value into the BackColor value in the property grid, eg:
150, 250, 70
You can use this method:
Color clr = Color.FromArgb(int alpha, int red, int green, int blue)
If you want this done using some User interface:
You could find out where the custom colors are stored for the current user, and then add one.
Or, create your own UITypeEditor, that contains the colors you want. Probably you have to inherit from Form, and override the BackColor property to add the correct attributes.
Much easier is to just set it in code, using the Argb code from the other answers.
You can not.
What you see is a default editor for Color type (create own control, add there public property of Color type and it will also uses it). Web and System tabs working fine. First tab is a sort of custom color pickup part from standard color pickup dialog.
I think MS fails to make popup editor to show modal dialog (because popup will get closed). =D
Perhaps colors there are taken from Windows color dialog, so you have to arrange it there (perhaps you can use winapi to do that). /shrug

Transparent form background with MenuStrip?

According to a lot of questions here on SO, the best way to make the background of a form transparent is to set it to a fairly unused color (like Magenta) then set the form's TransparencyKey to that color.
this.BackColor = Color.Magenta;
this.TransparencyKey = Color.Magenta;
That part works fine. The problem that I'm running into is that it works fine except behind a MenuStrip. A semi-transparent background in the MenuStrip + transparent background in the form ends up like this:
That's what the MenuStrip looks like. The part where it turns magenta is when the MenuStrip itself is set to be semi-transparent.
This is what my form initialization function looks like:
public frmMain() {
this.TransparencyKey = Color.Magenta;
InitializeComponent();
this.BackColor = Color.Magenta;
if(Properties.Settings.Default.windowTheme == 0) { // theme is light
menuStrip.Renderer = new ToolStripProfessionalRenderer(new LightTheme());
}
else if(Properties.Settings.Default.windowTheme == 1) {
menuStrip.Renderer = new ToolStripProfessionalRenderer(new DarkTheme());
}
menuStrip.Invalidate();
}
And my custom renderer for the MenuStrip (colors are just for testing right now):
public class LightTheme: ProfessionalColorTable {
public override Color MenuItemSelected {
get { return Color.FromArgb(255, Color.Yellow); }
}
public override Color MenuStripGradientBegin {
get { return Color.FromArgb(255, Color.Black); }
}
public override Color MenuStripGradientEnd {
get { return Color.FromArgb(0, Color.Gainsboro); }
}
}
What I'm really trying to accomplish here is having the form transparent and part of the MenuStrip transparent so you can see the desktop underneath it. Is there a better way to do it, or a way to fix this?
public override Color MenuStripGradientEnd {
get { return Color.FromArgb(0, Color.Gainsboro); }
}
This is where the problem started, you specified an alpha of 0 for the gradient end color. Which works nicely, the alpha is blended well. But it is applied to the background color. So you see a blend of magenta. Which no longer matches the color key so the pixels become visible.
The layered windows feature built into Windows support two ways to blend a window against the desktop, the underlying winapi call is SetLayeredWindowAttributes(). Winforms supports the LWA_COLORKEY option, enabled by setting the TransparencyKey property, but not the LWA_ALPHA option. Called "per-pixel alpha". You'll find plenty of google hints on the pinvoke you'd need to enable it.
But you'll then be in for a rude surprise, you'll see that most of the controls in the toolbox stop working. Text rendering in Winforms is done by GDI, an api that renders text with an alpha of 0. With the inevitable side-effect that, when you turn on per-pixel alpha, that text is now transparent as well. Which you could call a feature but drastically impractical since you don't control the desktop color nor what windows are behind yours.
That's fixable as well by replacing controls and use a text rendering api like DirectWrite. But that's rather a lot of work and you just don't get much benefit from Winforms anymore. WPF supports per-pixel alpha, it doesn't use the standard Windows controls.

C# UseVisualStyleBackColor

Is there a way in which I can change the button color and preserve the Windows VisualStyle? I want to create a button that looks like checkBox2 (color and style)
this.button2.BackColor = System.Drawing.SystemColors.GradientActiveCaption;
this.button2.UseVisualStyleBackColor = false; //if true, BackColor gets ignored
No, not really. This kind of button background is drawn by VisualStyleRenderer.DrawBackground(). Which in turns pinvokes DrawThemeBackground(). These methods don't take a color. None is needed because the color is already specified in the theme.
Simulating the appearance with a LinearGradientBrush is your only real hope. Note that custom drawing a button is quite difficult, all the code is internal and no owner-draw is provided.
Consider using an image.

Red-Green light indicators in C# .NET Form

What's the quickest way to show a red/green light indicator on a C# form?
I originally thought about using radio buttons, but not sure how to set the color of the dot, only the foreground/background text.
Then I thought about drawing a circle. Couldn't find a toolbox shape for that, and didn't want to write code just to draw the circle.
Basically, I'm writing a little application specific monitor, that shows a red light if certain services are down, or certain web services are not responding.
This is what I have so far using a square button instead of a circle. The code is just what I want, I just want a round shape.
if (allGood)
{
btnIISIndicator.BackColor = Color.Green;
}
else
{
btnIISIndicator.BackColor = Color.Red;
}
This is simple, just use System.Windows.Shapes for the object and System.Windows.Media.Brushes for the colors.
For a circle you can do the following:
System.Windows.Shapes.Ellipse circle = new System.Windows.Shapes.Ellipse();
circle.Height = 20; //or some size
circle.Width = 20; //height and width is the same for a circle
circle.Fill = System.Windows.Media.Brushes.Red;
Then you can make a function to do your check for red and green.
Also, you can use hex values for the colors as well:
circle.Fill = new System.Windows.Media.SolidColorBrush((Color)ColorConverter.ConvertFromString("#RRGGBB"));
Not exactly related to the question at hand, but your code could be shortened somewhat using the ternary operator as such:
btnIISIndicator.BackColor = allGood ? Color.Green : Color.Red;
But that all depends on your (or your organization's) definition of readability and maintainability.
I would just make a panel or PictureBox and set the Background image to that of a red/green light. Either make the images in PhotoShop/PaintShop/MS Paint or download some stock images off the web.
Whenever the status changes, just swap the image out.
just try this it works for me.
SolidColorBrush solidColor=new SolidColorBrush();
solidColor.Color=Colors.Red;
ellips_circle.Fill=solidColor;
Use an image, but theres some great icons available here so you dont have to actually make some.
Create red and green bitmaps and use the PictureBox control to show the bitmaps.
I just use some standard images and put them in a picturebox. works great on our apps.
I simply used a non enabled button as indicator since I did not manage to install the WinUI for shapes. Same suggestion as question but simplified.
indicatorButton.Enabled = false;
...
if (allGood)
{
indicatorButton.BackColor = Color.Green;
indicatorButton.Text = "On";
}
else
{
indicatorButton.BackColor = Color.Red;
indicatorButton.Text = "Off";
}

Categories