Visual Studios Win Form Properties.Settings Program Does Not Persist Across Computers

Hello, I wrote a small rudimentary program in C# for testing computers and their functionality at work. Just makes my job simpler/easier. I’ve been working to improve the program as needed by expanding it’s functionality and one feature I want is the ability to save the state of checkboxes. Properties.Settings was used in tandem with the following code:

private void Main_Load(object sender, EventArgs e)
       {
       checkCamera.Checked = Settings.Default.camera;
       checkArrowKeys.Checked = Settings.Default.arrowkeys;
       checkInternetAudio.Checked = Settings.Default.internetaudio;
       checkKeyboardLCD.Checked = Settings.Default.keyboardlcd;
       checkScreenBright100.Checked = Settings.Default.screenbrightness;
       checkConnectWiFi.Checked = Settings.Default.connectwifi;
       }
...

...
private void btnSave_Click(object sender, EventArgs e)
       {
       Settings.Default.camera = checkCamera.Checked;
       Settings.Default.arrowkeys = checkArrowKeys.Checked;
       Settings.Default.internetaudio = checkInternetAudio.Checked;
       Settings.Default.keyboardlcd = checkKeyboardLCD.Checked;
       Settings.Default.screenbrightness = checkScreenBright100.Checked;
       Settings.Default.connectwifi = checkConnectWiFi.Checked;
       Properties.Settings.Default.Save();
       }

This works running off a thumb drive with a very annoying caveat. If I unplug the thumb drive and plug it back into the same computer the settings were saved and reload. Perfect.

But, if I unplug it and then plug it into another computer it was never connected to before the settings do not persist. They go back to the forms checkbox defaults. This kind of defeats the purpose of what I want to use it for.

Now I should probably have stated this at the top but I’m a complete programming novice. I’ve been doing my best to research this on my own but I’m running out of word combinations to type into Google. :sweat_smile: The behavior tells me Properties.Settings doesn’t save the settings relative to the programs executable. Ie. They don’t get saved to the thumb drive but the system itself. Is there a simple work around? Or do I have to go down the rabbit hole that is figuring out how to write and load a custom .XML file?

Thank you!

Wouldn’t be easier to host the program on a local host instead of going terminal to terminal?

Unfortunately the purpose of my position is to physically test the condition of the computers hardware and software functionality. A tool that I can swap between 30, 40, 50+ computers a day is a necessity for the application. A localized install is not an option, neither is a network based service (working on convincing them to let me run a server though).

To be fully honest I’m amazed they’re letting me use this tool at all especially off a thumb drive. That’s usually one of the highest security risks but…I’m not going to complain.

1 Like

Oh I hear ya. Yes that is very true but I am sure they have ways of following your every step.

Settings in C# are saved under the users profile or in a system folder depending if you select per user or system storage.

You can either implement IPersistComponentSettings. Or perhaps the easier way: just save the settings in your own file on the USB stick by writing and reading the file.

To learn more about Settings and how it works: Application Settings Overview - Windows Forms .NET Framework | Microsoft Learn

All of the computers are logged in a Microsoft Access database via their S/N and to access this database I have to log in, meaning every computer S/N I worked on is tied to my login credentials. If any customer calls up the company saying they found something malicious on multiple PC’s that would very quickly come strait back to me. I know. :sweat_smile:

I could show you the full code if you want. Just be prepared to raise both eyebrows because I don’t entirely know what I was writing. Just that it works.

I’ll read the document you linked when I have time later today. Reading and writing the settings from the USB from a file would be most desirable. This would offer on the fly edits or debugging. The format I read about seems to typically be .XML. I’m just struggling to find forum posts or documentation my brain can decipher what I’m looking at so I can add the code and the .XML script if that’s what you had in mind.

It does look as though this will be the easier of the two. I finally tracked down something that provides a adequate example that I sort of understand: Writing XML with the XmlDocument class

Next question will be after I adapt this and write this…how do I read it…I know where to put it so it loads when the form loads just not what to write.

I think it would be easier to just write a text file with one line for each value. XML is a bit overkill for your example (if thats all the data you need to save, that you showed in your first post).

You could save each line as
checkCamera=true

for example.

And then you can extract the value by parsing each line.

index = line.IndexOf( “=” ) will get you the position of the = sign.
and then
valueName = line.Substring( 0, index )
valueData = line.Substring( index, line.Length )

As for reading and writing text files, take a look here: Read from and write to a text file by Visual C# - C# | Microsoft Learn

Also, my example code might not be correct. I haven’t done any programming in C# for over 10 years… but it should give you an idea where to start.

2 Likes

For the time being saving the state of these checkboxes is the only requirement but I do like the idea of having options. If going the .XML route opens up more possibilities to add considerably more complex features down the road I don’t mind investing the time.

Besides, even though it’s rough and it’s only one checkbox I just got it to work. :grin:

private void btnSave_Click(object sender, EventArgs e)
        {
            XmlDocument xmlDoc = new XmlDocument();
            XmlNode rootNode = xmlDoc.CreateElement("checkboxs");
            xmlDoc.AppendChild(rootNode);

            XmlNode functionNode = xmlDoc.CreateElement("checkbox");
            XmlAttribute attribute = xmlDoc.CreateAttribute("camera");
            attribute.Value = checkCamera.Checked.ToString();
            functionNode.Attributes.Append(attribute);
            rootNode.AppendChild(functionNode);

            xmlDoc.Save("./xml/test-doc.xml");

Which creates a file on it’s own containing:

<checkboxs>
  <checkbox camera="False" />
</checkboxs>

Then at Form Load:

XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load("./xml/test-doc.xml");
            XmlNodeList functionNodes = xmlDoc.SelectNodes("//checkboxs/checkbox");
            foreach (XmlNode functionNode in functionNodes)
            {
                if (functionNode.Attributes["camera"].Value == "False");
                {
                    checkCamera.Checked = false;
                }
            }

I have the Windows Form set to default the checkbox to checked so the fact it’s not sitting next to the others means it worked. Yay!

Now how to loop it in such a way that I don’t have to make 100 lines of code for 6 checkboxes… :thinking:

EDIT: I spoke too soon, no matter what I put in the IF condition it runs the contents. Dang it! >_<

1 Like

Got it working this time, tested before deployment so hopefully their computers don’t interfere somehow. I know there are better ways of coding this but at my current skill level it’s what I could come up with. I welcome criticism so long as it’s constructive.

The code:

private void xml(string input)
        {
            string[] checkboxes = { "Camera", "ArrowKeys", "InternetAudio", "KeyboardLCD", "ScreenBright100", "ConnectWiFi" };
            int count = 0;

            XmlDocument xmlDoc = new XmlDocument();

            if (input == "Load")
            {
            xmlDoc.Load("./xml/checkboxes.xml");
            XmlNodeList functionNodes = xmlDoc.SelectNodes("//checkboxes/checkbox");
                    
                foreach (XmlNode functionNode in functionNodes)
                {
                    if (count == 0) { if (functionNode.Attributes["Camera"].Value == "True") { checkCamera.Checked = true; } }
                    else if (count == 1) { if (functionNode.Attributes["ArrowKeys"].Value == "True") { checkArrowKeys.Checked = true; } }
                    else if (count == 2) { if (functionNode.Attributes["InternetAudio"].Value == "True") { checkInternetAudio.Checked = true; } }
                    else if (count == 3) { if (functionNode.Attributes["KeyboardLCD"].Value == "True") { checkKeyboardLCD.Checked = true; } }
                    else if (count == 4) { if (functionNode.Attributes["ScreenBright100"].Value == "True") { checkScreenBright100.Checked = true; } }
                    else if (count == 5) { if (functionNode.Attributes["ConnectWiFi"].Value == "True") { checkConnectWiFi.Checked = true; } }
                    count += 1;
                }
            }
            else if (input == "Save")
            {
                XmlNode rootNode = xmlDoc.CreateElement("checkboxes");
                xmlDoc.AppendChild(rootNode);

                foreach (string check in checkboxes)
                {
                    XmlNode functionNode = xmlDoc.CreateElement("checkbox");
                    XmlAttribute attribute = xmlDoc.CreateAttribute(check);
                    if (count == 0) { attribute.Value = checkCamera.Checked.ToString();}
                    else if (count == 1) { attribute.Value = checkArrowKeys.Checked.ToString(); }
                    else if (count == 2) { attribute.Value = checkInternetAudio.Checked.ToString(); }
                    else if (count == 3) { attribute.Value = checkKeyboardLCD.Checked.ToString(); }
                    else if (count == 4) { attribute.Value = checkScreenBright100.Checked.ToString(); }
                    else if (count == 5) { attribute.Value = checkConnectWiFi.Checked.ToString(); }
                    functionNode.Attributes.Append(attribute);
                    rootNode.AppendChild(functionNode);
                    count += 1;
                }
                xmlDoc.Save("./xml/checkboxes.xml");
            }
        }

This is called from Form_Load with xml("Load") and the Save Button with xml("Save")

This is the .XML file produced by the Save IF statement:

<checkboxes>
  <checkbox Camera="True" />
  <checkbox ArrowKeys="False" />
  <checkbox InternetAudio="False" />
  <checkbox KeyboardLCD="True" />
  <checkbox ScreenBright100="False" />
  <checkbox ConnectWiFi="True" />
</checkboxes>

I’m not a fan if using so many if, else if, and worse nested ifs but…I couldn’t think of anything else to make this work given I’m not calling simple variables but the form object.properties themselves.

If anybody wants to share how to do the same thing but better/smarter I’m open to learn something new. :slight_smile:

sorry for late reply, got the flu.

If would probably change the xml to something like this

<settings>
  <camera>true</camera>
</settings>

That way you can much easier access each setting with GetElementsByTagName. And you dont need the loop with the if count stuff.

Or if you want to keep the current structure. Instead of using the count variable. Check the attribute name and use that to control things. I think it would be good to keep the save and load function in such way its not dependent on the order of things. Especially if the file is opened in other programs or editors. XML does not guarantee the order of nodes.

1 Like

I prefer creating a class to hold settings and then serializing it into json personally. This looks like a good example for multiple methods: