Home > Software engineering >  C# ApplyTheme method to work on all forms simultaneously
C# ApplyTheme method to work on all forms simultaneously

Time:12-30

I'm trying to implement a theme changer to my app. So far I've done this:

BaseForm - has all the functions to be inherited from, it's a lengthy one so if required I'll post it here. What troubles I'm having is as follows:

MainForm has a button to open UserSettings where the user can change the theme. Problem is, I managed to get it down that the theme applies, but only for the UserSettings window, and I want it to apply to anything that is open (if there is anything else).

Edit: adding more code

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Text;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Windows.Forms;
using IniParser;
using ME___Tooling_Designer_App.Properties;

namespace ME___Tooling_Designer_App.Configuration;

public partial class UserSettings : BaseForm
{
    public UserSettings()
    {
        InitializeComponent();
        ApplyTheme();
        ReadConfiguration();
    }

// this is where the theme should be applied upon close
private void CBoxTheme_DropDownClosed(object sender, EventArgs e)
    {
        var parser = new FileIniDataParser();

        var data = parser.ReadFile(_filePathSettings);

        if (cBoxTheme.SelectedIndex == 0)
        {
            data["User_Settings"]["Theme"] = "Dark";
            parser.WriteFile(_filePathSettings, data);
            GlobalTheme = Enumerators.Theme.Dark;
        }

        if (cBoxTheme.SelectedIndex == 1)
        {
            data["User_Settings"]["Theme"] = "Light";
            parser.WriteFile(_filePathSettings, data);
            GlobalTheme = Enumerators.Theme.Light;
        }
        ApplyTheme();
    }

public override void ApplyThemeSpecific(ThemeSettings settings)
    {
        panel1.BackColor = settings.PrimaryColor;
        label2.ForeColor = settings.PrimaryFontColor;
        btnExit.BackColor = settings.PrimaryColor;
        btnExit.ForeColor = settings.PrimaryFontColor;
        groupBox1.ForeColor = settings.PrimaryFontColor;
        groupBox2.ForeColor = settings.PrimaryFontColor;

        panel2.BackColor = settings.SecondaryColor;
    }

Edit: this is BaseForm code:

using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Text;
using System.Windows.Forms;

namespace ME___Tooling_Designer_App.Configuration;

public class BaseForm : Form
{

    public static List<PrivateFontCollection> FontCollections;


    public static Enumerators.Theme GlobalTheme { get; set; }

    public void ApplyTheme()
    {
        var settings = new ThemeSettings();

        if (GlobalTheme == Enumerators.Theme.Dark)
        {
            settings.PrimaryColor = Color.FromArgb(32, 30, 50);
            settings.SecondaryColor = Color.FromArgb(32, 30, 45);
            settings.TertiaryColor = Color.FromArgb(11, 7, 17);
            settings.QuaternaryColor = Color.FromArgb(23, 21, 32);
            settings.QuinaryColor = Color.FromArgb(35, 32, 39);
            settings.SenaryColor = Color.LightGray;
            settings.SeptenaryColor = Color.Gainsboro;
            settings.PrimaryFontColor = Color.Gainsboro;
        }

        else if (GlobalTheme == Enumerators.Theme.Light)
        {
            settings.PrimaryColor = Color.LightGray;
            settings.SecondaryColor = Color.GhostWhite;
            settings.TertiaryColor = Color.Gainsboro;
            settings.QuaternaryColor = Color.DarkGray;
            settings.QuinaryColor = Color.Silver;
            settings.SenaryColor = Color.Gray;
            settings.SeptenaryColor = Color.Black;
            settings.PrimaryFontColor = Color.Black;
        }

        ApplyThemeSpecific(settings);
    }

    public virtual void ApplyThemeSpecific(ThemeSettings settings)
    {
    }
}

public class Enumerators
{
    public enum Theme
    {
        NotSet,
        Light,
        Dark
    }
}

public class ThemeSettings
{
    public Color PrimaryColor { get; set; }
    public Color SecondaryColor { get; set; }
    public Color TertiaryColor { get; set; }
    public Color QuaternaryColor { get; set; }
    public Color QuinaryColor { get; set; }
    public Color SenaryColor { get; set; }
    public Color SeptenaryColor { get; set; }
    public Color PrimaryFontColor { get; set; }
}

this is my Program.cs:

using System;
using System.Windows.Forms;
using IniParser;
using ME___Tooling_Designer_App.Configuration;
using ME___Tooling_Designer_App.Forms;

namespace ME___Tooling_Designer_App
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {

            var parser = new FileIniDataParser();

            var data = parser.ReadFile(Application.StartupPath   @"\"   "Config"   @"\"   "settings.ini");

            var themeSetting = data["User_Settings"]["Theme"];

            Application.EnableVisualStyles();
            Application.SetHighDpiMode(HighDpiMode.SystemAware);
            Application.SetCompatibleTextRenderingDefault(false);
            if (themeSetting == "Light")
            {
                BaseForm.GlobalTheme = Enumerators.Theme.Light;
            }
            else if (themeSetting == "Dark")
            {
                BaseForm.GlobalTheme = Enumerators.Theme.Dark;
            }
            else
            {
                BaseForm.GlobalTheme = Enumerators.Theme.NotSet;
            }

            Application.Run(new Login());
        }

    }
}

tried doing it as MainForm.ApplyTheme, but that just returns to UserSettings nonetheless

Edit: adding snippets of MainForm:

namespace ME___Tooling_Designer_App.Forms;

public partial class MainForm : BaseForm
{
    /// <summary>
    ///     Constructor
    /// </summary>
    public MainForm()
    {
        InitializeComponent();
        ApplyTheme();
        CreateDirectories();
        CustomizeDesign();
        InitializeDatFiles();
        InitializeIniConfiguration();
        ReadFont();
        ReadComputer();
        ReadSystem();
        TestTrial();
        DaysRemainColoring();
        CompareComputerNameAndLicense();
        lblUser.Text = Environment.UserName;
    }

public override void ApplyThemeSpecific(ThemeSettings settings)
    {
        panelTopBar.BackColor = settings.PrimaryColor;
        btnInfo.BackColor = settings.PrimaryColor;
        btnMinimize.BackColor = settings.PrimaryColor;
        btnExitTop.BackColor = settings.PrimaryColor;

        panelCenter.BackColor = settings.SecondaryColor;

        panelSideMenu.BackColor = settings.TertiaryColor;
        panelSideMenuLogo.BackColor = settings.TertiaryColor;
        btnMainMenu.BackColor = settings.TertiaryColor;
        btnSettings.BackColor = settings.TertiaryColor;
        btnSave.BackColor = settings.TertiaryColor;
        btnLoad.BackColor = settings.TertiaryColor;
        btnExit.BackColor = settings.TertiaryColor;

        panelQuickView.BackColor = settings.QuaternaryColor;

        panelMainMenu.BackColor = settings.QuinaryColor;
        panelSettings.BackColor = settings.QuinaryColor;
        btnNewProject.BackColor = settings.QuinaryColor;
        btnExistingProject.BackColor = settings.QuinaryColor;
        btnReadProject.BackColor = settings.QuinaryColor;
        btnSearchProject.BackColor = settings.QuinaryColor;
        btnUserSettings.BackColor = settings.QuinaryColor;
        btnAppSettings.BackColor = settings.QuinaryColor;
    }

CodePudding user response:

The solution is to add a timer

Because your problem is to update all windows, you just need to add a timer control to each window.

Timer:

enter image description here

BaseForm:

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

namespace WindowsFormsApp4 {
    public partial class BaseForm : Form {
        public BaseForm () {
            }
        private static Image baseImage=null;
        public static Image BaseImage {
            get {
                return baseImage;
                }
            set {
                baseImage = value;
                }
            }
        }
    }

SettingsForm:

using System;

namespace WindowsFormsApp4 {
    public partial class SettingsForm : BaseForm {
        public SettingsForm () {
            InitializeComponent();
            }

        private void button1_Click (object sender, EventArgs e) {
            BaseImage = Resource.tiger;
            }

        private void button2_Click (object sender, EventArgs e) {
            BaseImage = Resource.windows;
            }

        private void timer1_Tick (object sender, EventArgs e) {
            this.BackgroundImage = BaseImage;
            }
        }
    }

Form1:

using System;

namespace WindowsFormsApp4 {
    public partial class Form1 : BaseForm {
        public Form1 () {
            InitializeComponent();          
            }
        private void button1_Click (object sender, EventArgs e) {
            SettingsForm settingsForm=new SettingsForm();
            settingsForm.ShowDialog();
            }

        private void timer1_Tick_1 (object sender, EventArgs e) {
                this.BackgroundImage = BaseImage;
            
            }
        }
    }

Resource.resx:

enter image description here

OutPut:

enter image description here

You can change it according to your needs.

If you have any questions, please comment below, and I will continue to follow up.

CodePudding user response:

Try this code on all forms of your project on Activated and Load events.

Such as, MainForm:

    private void MainForm_Activated(object sender, EventArgs e)
    {
         ApplyTheme();
    }

Update: Try following line on BaseForm, if it works, add override on all forms and change the color values of all elements:

public virtual void ApplyThemeSpecific(ThemeSettings settings)
{
     Background = settings.PrimaryColor; //for example
}

Update 2: Add a timer on all forms that checks theme change, and when theme changes, it changes the visual. Or you can make a event when theme changes.

  • Related