Click here to Skip to main content
15,911,646 members
Please Sign up or sign in to vote.
4.00/5 (2 votes)
See more:
There are various controls including buttons, radio buttons, textboxes and datagridview on my form. There are many forms.

I want to provide a facility to the user for changing color theme for these controls including the forms.
For e.g., if user chooses a Black theme option, all controls must have background color set to black. If Blue, then controls must be having blue background.

One way to accomplish this task is I can create a User Control for a button with manual color. But this creates a problem. After debugging the control is now bounded to a specific color set in code file. Thus, user can not switch from one theme to another.

Another way I thought of is to create a class with different defined visuals (colors, font, etc) for controls and then reference the properties of the controls to that class, individually, for each control on each form. This will be very lengthy and tough task to execute.

I need a guidance to a more simple approach, so that I can provide such facility.
Let me know if there are any confusions regarding this question.

What I have tried:

Tried creating user defined controls for specific themes, but its not the solution.
Posted
Updated 8-May-16 10:22am
Comments
Richard MacCutchan 8-May-16 3:31am    
Why not just iterate through your controls and set the background (or any other) colours to the ones chosen by the user? You say it will be very lengthy to execute, but it will still take a lot less time than the user will take in selecting the colours.
Philippe Mori 8-May-16 16:36pm    
Might make more sense to switch to WPF or use controls specidically designed for theming.

Here's a rough "skeleton" of what the beginnings of a style manager for WinForms might look like:
C#
public static class VisualStyleManager
{
   public static Dictionary<string, VisualStyle> StyleDictionary { set; get; }

   public static void AddStyle(string name, Control control)
   {
        StyleDictionary.Add(name, new VisualStyle(control));
   }
 
   public static void ApplyStyle(string stylename, Control control)
   {
       VisualStyle style;

       if(StyleDictionary.TryGetValue(stylename, out vs)
       {
           control.BackColor = vs.BackColor;
           control ForeColor = vs.ForeColor;
           control.Font = vs.Font;
       }     
   }
}

public class VisualStyle
{
    public Color CBackColor { set; get; }
    public Color CForeColor { set; get; }

    public Font CFont {set; get; }

    public VisualStyle(Control control)
    {
        CBackColor = control.BackColor;
        CForeColor = control.ForeColor;
        CFont = control.Font;
    }
}
Here's how it might be used:
C#
private void SetAllFormButtons(Form form, button abutton)
{
   VisualStyleManager.AddStyle("ButtonStyle1", button1);

   foreach (var btn in this.GetControlsByType<Button>())
   {
       if (btn != button1)
       {
           VisualStyleManager.ApplyStyle("ButtonStyle1", btn);
       }
   }
}
This makes use of an extension Method:
C#
public static class ControlExtensions
{
    public static IEnumerable<Control> GetControlsByType<T>(this Control control)
    {
        Stack<Control> stack = new Stack<Control>();

        stack.Push(control);

        while (stack.Any())
        {
            Control nextcontrol = stack.Pop();

            foreach (Control childControl in nextcontrol.Controls)
            {
                stack.Push(childControl);
            }

            if (nextcontrol is T) yield return nextcontrol;
        }
    }
}
Now consider what you are going to have to deal with to make this handle WinForm Control Properties like a Form's 'FormBorderStyle, or a Button's FlatStyle, and FlatAppearance Properties; these Properties are not exposed when you cast these Controls to their Control base Type.

For every unique Control Type's Property, you will have to handle that as a special case. However, there are other ways, making heavy use of 'Reflection, to do this. And, you can take the "skeleton" here and sub-class VisualStyle to handle other Control Types with "special requirements."

By now, you may have figured out that to get anything substantial going with theming involves (probably) a lot of work on your part. While doing this may improve your design skills and knowledge of WinForms internals, if you are at a relatively early phase in studying and using WinForms and C#, I suggest you do not take on trying to write a full-featured theme facility.

There are other strategies you could pursue: such as, displaying a Property Browser at run-time to let the user edit colors, fonts, etc. Let's say User1 edited the BackColor of any one Button; you could get a notification of that event and then set all the other Buttons to use that same BackColor.
 
Share this answer
 
v3
 
Share this answer
 
Comments
Member 11040029 8-May-16 3:27am    
Update and apologies to my reply <please read the question carefully and then post an answer>

Went through the above link, but things were not clear at first, but you provided me with the exact solution required. It would be great if u can mention a bit more information regarding your search in future.
Garth J Lancaster 8-May-16 4:53am    
Thats pretty rude - you were given a 'more simple' answer and different approach from either of the two that you suggest, but it would be my first approach also.

How does Richard's answer not help you ? I dont see a nice reply to him asking for more information .. if I were him, luckily Im not, I wouldnt bother answering any more questions from you (he's probably nice than I am)
Member 11040029 9-May-16 6:35am    
I am sorry for that behaviour. But what do I think about codeproject is that it's a community where we can discuss on things rather than posting to google on something. If someone is posting a question on our beloved codeproject, then, it might be that he has already googled for the query or tried something himself.
I request to the intellectual guys here, please consider questions for an answer and not just saying that google it with some keyword.
I am again very sorry to the Richard and to you to Garth for the behaviour but it was just a natural one cause I was tired of googling for a exact optimised and convenient way for my need.
Richard MacCutchan 9-May-16 6:40am    
Well firstly, we do not know what you have Googled for. And even when we see questions that say "I have searched everywhere", we often find the answer by posting their question into Google.

Secondly, it is not always likely that you will find the exact answer to your problem. You will more likely find different suggestions, ideas, code snippets which you need to adapt to get your code to do what it wants.
Sergey Alexandrovich Kryukov 8-May-16 9:18am    
5ed.
—SA
If you want to use skinning for winforms take a look at these:

A New Skin for Ye Olde GroupBox[^]

The Grouper - A Custom Groupbox Control[^]

GUI Skinning System for Windows Forms .NET[^]

As suggested by Richard you can iterate through the Control collection, here is an example:
C#
/// <summary>
/// Get the text for Form controls from Resource1
/// </summary>
private void TranslateForm()
{
    string formName = this.Name + "_";
    string str;
 
    foreach (Control ctrl in this.Controls)
    {
        System.Diagnostics.Debug.Print(formName + ctrl.Name);
        System.Diagnostics.Debug.Print(ctrl.GetType().ToString());          // e.g. System.Windows.Forms.Label
        try
        {
            str = Resource1.ResourceManager.GetString(formName + ctrl.Name);        // Form1_lblAddress etc.
            ctrl.Text = str;
        }
        catch (Exception)
        {
            Debug.Print(".");
        }
    }
}
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900