locked
How to use Application Settings for a config form? RRS feed

  • Question

  • Hello,

    I've got a simple alarm clock I'm working on which currently has two forms, formClock.cs, and formConfig.cs.  I know there are a few ways this can be done either through an .ini or similar file on the client's computer, or with application settings.  I'm interested in trying application settings and have seen a few videos on the subject, but none of them show how to setup a config form for passing variables to the application form.

    Any help appreciated as always!

    Steve

    Monday, November 26, 2012 9:13 PM

Answers

  • Tell you what, let me create a test application. Just click here and press enter to download.

    Below is what I did:
    ====================

    • created a brand new C# console project
    • added App.config (right click on solution --> Add --> Add
    • new item --> "Applicaiton Configuration File")
    • Add referance to "System.configuration" assembly
    • add using directove to the .cs(es) where you want to
    • access the values from .config
    • wrote some code, added a class file Program2.cs (Right
    • click on solution --> Add --> class
    • called the 'print' method of Program2 class.

    Code Snip:

    App.config file:
    ----------------
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <appSettings>
        <add key="key1" value="this is the value 1 from app.config"/>
        <add key="key2" value="this is the value 2 from app.config, just like that !"/>
      </appSettings>
    </configuration>

    using System.Configuration;

    if (ConfigurationManager.AppSettings["key1"] != null) // its a good practice to check for nulls so that the program does not throw an exception at run times.
                {
                    k1 = ConfigurationManager.AppSettings["key1"].ToString();
                    Console.WriteLine(k1);
                }

    Added another class:

    using System.Configuration;
    
    namespace AccessingTheConfigurationsWithConfig
    {
        class Program2
        {
            public void print()
            {
                string k2 = string.Empty;
                if (ConfigurationManager.AppSettings["key2"] != null) 
                // its a good practice to check for nulls so that the program does not throw an exception at run times.
                {
                    k2 = ConfigurationManager.AppSettings["key2"].ToString();
                    Console.WriteLine(k2);
                }
            }
        }
    }

    Invoking form the main class:

                Program2 p2 = new Program2();
                p2.print();
    Output:

    ===============================
    this is the value 1 from app.config
    this is the value 2 from app.config, just like that

    Please mark the post as an answer that helps/solves your issue, thanks !

    • Edited by Aarsh (MCTS) Wednesday, December 5, 2012 8:09 PM to add code snippets
    • Proposed as answer by Bob Shen Thursday, December 6, 2012 3:30 AM
    • Marked as answer by Bob Shen Friday, December 7, 2012 9:51 AM
    Monday, December 3, 2012 10:03 PM
  • That's because once Form2 closes, your reference to it in Form1 (frm2) gets disposed. You can handle it one of two ways:

    1) Show frm2 with .ShowDialog() instead of .Show(). Then your frm2 instance will not be disposed.

    2) Use a Forms Handler, as I describe in my blog post:

    http://geek-goddess-bonnie.blogspot.com/2012/04/forms-handler.html


    ~~Bonnie Berent DeWitt [C# MVP]

    geek-goddess-bonnie.blogspot.com

    • Proposed as answer by Naomi N Sunday, December 9, 2012 8:43 PM
    • Marked as answer by Bob Shen Monday, December 10, 2012 7:43 AM
    Sunday, December 9, 2012 5:45 PM

All replies

  • Here is how you add those variables as keys:

    .config <?xml version='1.0' encoding='utf-8'?> <configuration> <startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0"/> </startup> <connectionStrings> <add name="CherokeeMagistrate" providerName="System.Data.ProviderName" connectionString="*****"/> <add name="IconConnection" providerName="System.Data.ProviderName" connectionString="*****"/> </connectionStrings> <appSettings> <add key="logFilePath" value="C:\Logs\CoversionLog.txt"/> ... </appSettings>

    </configuration>


    and here is how you access them :

    string _LogFile = ConfigurationManager.AppSettings["logFilePath"].ToString();

    Once you do this it is a good practice to check the C# variable against NULL as

    //pseudo code 
    ==============
    
    if(!string.IsNullOrEmpty(_LogFile ))
    {
         // do your stuff
    }
    else
    {
        // you got a situation, handle it !
    }


    • Proposed as answer by Norkk Tuesday, November 27, 2012 11:06 AM
    • Edited by Aarsh (MCTS) Monday, December 3, 2012 11:34 AM
    Monday, November 26, 2012 9:57 PM
  • I put the form1 code and the form2 code into the file form1.cs to make it easier to show how this is done.  I create form1 with just a button and form2 with just a text box.  I then created a function in form2 class that take a passed parameter writes to a textbox.

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            Form2 form2 = new Form2();
            public Form1()
            {
                InitializeComponent();
               
            }
            private void button1_Click(object sender, EventArgs e)
            {
                form2.writetextbox("message");
                form2.Show();
            }
        }
        public partial class Form2 : Form
        {
            public Form2()
            {
                InitializeComponent();
            }
            public void writetextbox(string message)
            {
                textBox1.Text = message;
            }
        }
    }


    jdweng

    Monday, November 26, 2012 9:58 PM
  • Hey guys.  Thanks for the responses.  The first one, I'm not sure how that relates to my issue as it "appears" to be ASP.NET code, but not sure.  The second one, dealing with passing variables is helpful, however I still need to understand how to allow a user to choose settings on a config form, have those settings apply to a "master" form, then have those settings be saved when the user reloads the application.

    Example in my case:  I have a clock program.  In it are two forms (formClock.cs, and formConfig.cs).  formClock.cs has a timer control which tests for time of day and depending on that, plays some audio files at different times of the day.  The clock uses two labels for displaying a date and time.  I also have this clock being forced to the user's second monitor, and using the notify icon and contextstrip controls to allow the user to pull up a config form to change various things like color of clock text, turn alarm on or off, and set alarm time.

    Currently the config form is not wired so to speak (just controls).  I want to be able eventually wire these components in the config form to control the various attributes of the clock form, and have them save per user.  I'm not tied to any particular method of doing the saving, be it either using Appplication Settings, or creating an external config file of some kind (neither of which I know how to do).  I am a newbie to Visual C#, but eager to learn.

    So in a nutshell I have two major needs:  Learn to pass variables or settings from one form to another, and learn to save user settings.

    Hopefully this sheds some more light on what I'm trying to accomplish, and if not please let me know as I'm really wanting to learn how to do all of this.

    Friday, November 30, 2012 2:21 PM
  • Load the code in my last posting into a new project.  Add a 2nd form by going to project menu add new item and select form.  YOu will then have two forms in the project.  I think that will answer all your questions.  It doesn't matter if the code is in one cs file or two cs files as long as the namespace is the same.

    jdweng

    Friday, November 30, 2012 3:13 PM
  • The code I suggested, is being used in a Console application, hence it may be used for console / web application. I can share a couple links for app.config file.

    Please give a shot to what is suggested. &I hope this helps, please post if you have further queries.

    Please mark the post as an answer that helps/solves your issue, thanks !


    Monday, December 3, 2012 11:33 AM
  • Please share the links.  Nothing I am doing is working.  I can get the code that Joel provided to work no problem, but it doesn't help me understand fully how to create variables in one form from the particular state of a control on that form, then using that variable, change the property or state of a control on another form, then save all that so that the user doesn't have to redo it all next time the application is opened.
    Monday, December 3, 2012 9:19 PM
  • Tell you what, let me create a test application. Just click here and press enter to download.

    Below is what I did:
    ====================

    • created a brand new C# console project
    • added App.config (right click on solution --> Add --> Add
    • new item --> "Applicaiton Configuration File")
    • Add referance to "System.configuration" assembly
    • add using directove to the .cs(es) where you want to
    • access the values from .config
    • wrote some code, added a class file Program2.cs (Right
    • click on solution --> Add --> class
    • called the 'print' method of Program2 class.

    Code Snip:

    App.config file:
    ----------------
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <appSettings>
        <add key="key1" value="this is the value 1 from app.config"/>
        <add key="key2" value="this is the value 2 from app.config, just like that !"/>
      </appSettings>
    </configuration>

    using System.Configuration;

    if (ConfigurationManager.AppSettings["key1"] != null) // its a good practice to check for nulls so that the program does not throw an exception at run times.
                {
                    k1 = ConfigurationManager.AppSettings["key1"].ToString();
                    Console.WriteLine(k1);
                }

    Added another class:

    using System.Configuration;
    
    namespace AccessingTheConfigurationsWithConfig
    {
        class Program2
        {
            public void print()
            {
                string k2 = string.Empty;
                if (ConfigurationManager.AppSettings["key2"] != null) 
                // its a good practice to check for nulls so that the program does not throw an exception at run times.
                {
                    k2 = ConfigurationManager.AppSettings["key2"].ToString();
                    Console.WriteLine(k2);
                }
            }
        }
    }

    Invoking form the main class:

                Program2 p2 = new Program2();
                p2.print();
    Output:

    ===============================
    this is the value 1 from app.config
    this is the value 2 from app.config, just like that

    Please mark the post as an answer that helps/solves your issue, thanks !

    • Edited by Aarsh (MCTS) Wednesday, December 5, 2012 8:09 PM to add code snippets
    • Proposed as answer by Bob Shen Thursday, December 6, 2012 3:30 AM
    • Marked as answer by Bob Shen Friday, December 7, 2012 9:51 AM
    Monday, December 3, 2012 10:03 PM
  • Aarsh,

    Thank you very much for the time and effort to write that example.  It helps me understand the app.config file more, but I still have lots of questions, so please bear with me.  I think if I can get a few basic concepts down I'll be good to go.

    I decided to step back from trying to force my existing application to work the way I want it to, and created a simple program for learning.  My goal in this exercise is to be able to select a radio button on Form1, store the value of the "color", have that "color" value transfer to the label on Form2 and also have the radio button choice stored so that when the app is closed and run again, it will be the same as it was when it was closed.

    Form1 contains a group box with two radio buttons. radioButton1 is labeled Red, radioButton2 is labled Blue. There is a Save button on Form1. The save button's job will be to check which of the radio buttons is selected, then transfer that info somewhere (either app.config or settings.settings for storage), then ultimately have the label on Form2 change color based on the radio button selection.

    Form1:


        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
            Form2 form2 = new Form2();
            private void Form1_Load(object sender, EventArgs e)
            {
            }
            private void button1_Click(object sender, EventArgs e)
            {
                string lblcolor;
                if (radioButton1.Checked == true)
                {
                    lblcolor = "color.red";
                }
                if (radioButton2.Checked == true)
                {
                    lblcolor = "color.blue";
                }
                form2.labelColor(lblcolor);
                form2.Show();
            }
        }

    Form 2

     public partial class Form2 : Form
        {
            public Form2()
            {
                InitializeComponent();
            }
            public void labelColor(string lblcolor)
            {
                label1.ForeColor = lblcolor;
            }
            private void Form2_Load(object sender, EventArgs e)
            {
            }
        }

    Errors so far:

    Cannot implicitly convert type 'string' to 'System.Drawing.Color' - Form2.cs:

    label1.ForeColor = lblcolor;

    Use of unassigned local variable 'lblcolor'

    form2.labelColor(lblcolor);

    If you could please just take a look at this and let me know where I'm missing something I'd appreciate it.  Please keep in mind that I still need to be able to make these settings save somehow based on user selection too.

    Thank you so much for helping me out!

    Steve

    Friday, December 7, 2012 4:50 PM
  • Steve, there may be multiple different scenarios either-way. I just posting some possible way outs:

    class Form1 {
      public string MyValue {
        get { return textBox1.Text; }
      }
    }

    And then access it from Form2:

    var frm1 = new Form1();
    frm1.ShowDialog(this); // make sure this instance of Form1 is visible
    textBox1.Text = frm1.MyValue; //This text box is on form 2

    Please mark all posts as 'helpful' that helps and mark all those posts as answer that you think are the answers.


    Aarsh Talati, MCTS


    Friday, December 7, 2012 7:30 PM
  • I wrote this little program to help me understand how to save settings.  I know I'm making seasoned programmers laugh but this really is not clicking with me.

    This program consists of a single form that has 2 default radio buttons and a Save button.  I want to be able to tick either radio button and have it save to my settings.settings file, then have the saved radio button still be checked.

    Settings.settings file:
    Name: radio_default
    Type: int
    Scope: User
    Value: 1

    Form1's code below:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Configuration;
    
    namespace settings
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            public int radioSetting;
    
            private void btnSave_Click(object sender, EventArgs e)
            {
                if (radioButton1.Checked == true)
                {
                    radioSetting = 1;
                }
    
                else
                {
                    if (radioButton2.Checked == true)
                    {
                        radioSetting = 2;
                    }
                }
    
                Properties.Settings.Default.radio_default = radioSetting;
                Properties.Settings.Default.Save();
    
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                if (Properties.Settings.Default.radio_default == 1)
                {
                    radioButton1.Checked == true;
                }
    
                else
                {
    
                    if (Properties.Settings.Default.radio_default == 2)
                    {
                        radioButton2.Checked == true;
                    }
                }
            }
              
        }
    }
    

    Errors:
    "Only assignment, call, increment, decrement, and new object expressions can be used as a statement"

    I'm getting that statement on both lines at the bottom that contain "radioButton(1 or 2).Checked == true;

    So short of my errors, am I on the right track for being able to save settings?

    Saturday, December 8, 2012 7:49 PM
  • You error message is due to having two equal signs in the statement instead of one.  Two equal signs are used when you are testing for a condition (like in a iIF statement).  One equal sign is used for assignments.  You are assigning the check box value to a true.

    You are always onb the right track by writing short pieces of code to help understand of find the root cause of an error.  I've been writing software for over 30 years and often test small pieces of test code to help solve problems.

    Usually setting are run time options and should be either in a Menu item or in a file like an XML file.  I would rather write my own initialization function than use a burried menu option like the system settings.  System Settings file is not port to another compiler and table, and may be missed by other programmers who work on the project because it is in a subfolder and not on the same folder level as the rest of the source code.


    jdweng

    Sunday, December 9, 2012 1:02 AM
  • Wow, thank you Joel.  I should have known that.  Well after getting rid of the double equals signs, my program works.  I can select radio button 2, hit save button, exit the program and when I restart the program radio button 2 is still selected.  I agree about the settings at runtime.  There a few options that I want to be permanent between runs though and I had to figure that out before moving on.  I think with all you experience programmers behind me, I'll be able to accomplish my goals :)

    Sunday, December 9, 2012 2:13 PM
  • OK, here's the final piece of the puzzle that needs to be answered.  I've expanded my little test program that I'm using to learn settings to 2 forms.

    The scenario:  Select a radio button on Form1 which will change the color of a label on Form2.

    Currently, I can open Form1, choose a radio button, click the save button and Form2 shows with proper label forecolor as selected by the radio button.  If I close Form2, select another radio button on Form1 and click Save again (which normally spawns Form2), I get an error on frm2.Show(): ObjectDisposedException was unhandled / Cannot access a disposed object.

    Form1:

    namespace settings { public partial class Form1 : Form { public Form1() {
    InitializeComponent(); } // Declare variables public int radioSetting; // Variable will be written to radio_state in settings.settings public bool cb1Setting; // Variable will be written to cb1_state in settings.settings public bool cb2Setting; // Variable will be written to cb2_state in settings.settings Form2 frm2 = new Form2(); // Create new Form2 object to access it from Form1 private void btnSave_Click(object sender, EventArgs e) { // This IF block evaluates which controls are selected // Assigns a value to variable radioSetting // Passes a color value to the Lable (f2_lblColor) on Form2 if (radioButton1.Checked == true) { radioSetting = 1; frm2.f2_lblColor = Color.Cyan; } if (radioButton2.Checked == true) { radioSetting = 2; frm2.f2_lblColor = Color.Magenta; } if (radioButton3.Checked == true) { radioSetting = 3; frm2.f2_lblColor = Color.Yellow; } if (radioButton4.Checked == true) {
    radioSetting = 4; frm2.f2_lblColor = Color.White; } if (checkBox1.Checked == true) { cb1Setting = true; } if (checkBox2.Checked == true) { cb2Setting = true; } // Set and save variables to settings.settings Properties.Settings.Default.radio_state = radioSetting; Properties.Settings.Default.cb1_state = cb1Setting; Properties.Settings.Default.cb2_state = cb2Setting; Properties.Settings.Default.Save(); frm2.Show(); }

    private void Form1_Load(object sender, EventArgs e) { // This IF block checks appropriate radio button based // on value of radio_state in settings.settings if (Properties.Settings.Default.radio_state == 1) { radioButton1.Checked = true; } if (Properties.Settings.Default.radio_state == 2) { radioButton2.Checked = true; } if (Properties.Settings.Default.radio_state == 3) { radioButton3.Checked = true; }

    if (Properties.Settings.Default.radio_state == 4) { radioButton4.Checked = true; } if (Properties.Settings.Default.cb1_state == true) { checkBox1.Checked = true; } if (Properties.Settings.Default.cb2_state == true) { checkBox2.Checked = true; } } private void btnCancel_Click(object sender, EventArgs e) { this.Close(); } } }

    Form2:
    namespace settings
    {
    public partial class Form2 : Form
    {
    public Form2()
    {
    InitializeComponent();
    }
    
    // Declare public variables so other forms can access
    public Color f2_lblColor;
    private void Form2_Load(object sender, EventArgs e)
    {
    // Retrieve value of lable forecolor from Form1
    label1.ForeColor = f2_lblColor;
    }
    
    private void Form2_MouseClick(object sender, MouseEventArgs e)
    {
    this.Close();
    }
    private void label1_MouseClick(object sender, MouseEventArgs e)
    {
    this.Close();
    }
    }
    }
    Help much appreciated as always C# gurus!

    Steve



    • Edited by SJurick Sunday, December 9, 2012 4:57 PM
    Sunday, December 9, 2012 4:47 PM
  • That's because once Form2 closes, your reference to it in Form1 (frm2) gets disposed. You can handle it one of two ways:

    1) Show frm2 with .ShowDialog() instead of .Show(). Then your frm2 instance will not be disposed.

    2) Use a Forms Handler, as I describe in my blog post:

    http://geek-goddess-bonnie.blogspot.com/2012/04/forms-handler.html


    ~~Bonnie Berent DeWitt [C# MVP]

    geek-goddess-bonnie.blogspot.com

    • Proposed as answer by Naomi N Sunday, December 9, 2012 8:43 PM
    • Marked as answer by Bob Shen Monday, December 10, 2012 7:43 AM
    Sunday, December 9, 2012 5:45 PM
  • Bonnie (or anyone really),

    I've now got enough ammunition through the example program to attack my original clock program again.  When I start my clock app, I'm presented with the Config form.  Here you can change various settings for the Clock form.  When you click Save, all the settings save to the settings.settings file and the Clock form opens.  One of the main features of this program is that you can choose which monitor to have the Clock form open on.  This works, but when the Clock form opens, the Config form remains, but locked so to speak - I can't click anything on it.  The Clock form opens on the selected monitor as expected with all the parameter settings changes that were selected on the Config form.

    Now the Config form has a ContextMenuStrip so that the user can either pull up the Config form to change things, or exit the program.  If I click on the ContextMenu and choose Config, another Config form is instanced and I can make changes (but there are now two Config forms active).

    How can I make it to where when I click the Save button, the Clock form opens and the Config form closes, but still have the ability to have the ContextMenu running?  I've tried putting the ContextMenu on the Clock form but that really has the same effect.

    Here's the Save button's code:

    private void btnStart_Click(object sender, EventArgs e)
    {
     if (rbMon1.Checked == true)
    {
    Properties.Settings.Default.set_monitor = 0;
    Properties.Settings.Default.Save();
    frmclk.monitor = 0;
    }
    
     if ( rbMon2.Checked == true)
    {
    Properties.Settings.Default.set_monitor = 1;
    Properties.Settings.Default.Save();
    frmclk.monitor = 1;
    }
    MessageBox.Show("Monitor value currently " + Properties.Settings.Default.set_monitor);
    frmclk.ShowDialog();
    }

    Any ideas on this please?  I'm really close now I can feel it.


    • Edited by SJurick Tuesday, December 11, 2012 3:34 AM
    Tuesday, December 11, 2012 3:32 AM
  • try removing the code below

    private void btnCancel_Click(object sender, EventArgs e)
    {
    this.Close();
    }

    I think the close is disposing the form1 class.  The next time you use the context menu it is constructing the class again.  If you don't do the close you won't dispose the class.

    jdweng

    Tuesday, December 11, 2012 10:21 AM
  • Well, you're opening your Clock form (frmclk) as a Dialog, so that's why you can't click on the Config form. If your purpose is to be able to use both the Config form and the Clock form at the same time, then you'll  need to use .Show() instead of .ShowDialog(). I *think* this is what you're asking about anyway ...

    ~~Bonnie Berent DeWitt [C# MVP]

    geek-goddess-bonnie.blogspot.com

    Tuesday, December 11, 2012 3:38 PM
  • Bonnie,

    Yes, the idea is to have both running at the same time, but have the config form be called up at any time using the context menu, without either form winding up running multiple times.

    Is there a slick way to fire off the forms and check that if one is already running, to not instance it again?

    Steve

    Wednesday, December 12, 2012 1:57 AM
  • Is there a slick way to fire off the forms and check that if one is already running, to not instance it again?

    Yep, I posted a link to it already in a previous reply ... my blog post about using a Forms Handler:

    http://geek-goddess-bonnie.blogspot.com/2012/04/forms-handler.html


    ~~Bonnie Berent DeWitt [C# MVP]

    geek-goddess-bonnie.blogspot.com

    Wednesday, December 12, 2012 2:20 AM