I need to pragmatically update an auto generated app.config file of a Windows Form.
Specifically an ArrayOfStrings.
Desired out put:
<setting name="Test" serializeAs="Xml">
<value>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>Test 1</string>
<string>Test 2</string>
<string>Test 3</string>
</ArrayOfString>
</value>
</setting>
What my code generates:
<setting name="Test" serializeAs="Xml">
<value>New Data 3</value>
</setting>
I have researched Xml serialization, but it is completely new to me and I am struggling to figure it out.
public void saveCardDataToSettings() {
List<String> DetectorCardTypeData = new List<string>();
foreach (DataGridViewRow row in dgvDetectorCardData.Rows)
{
string CurrentRowData = (row.Cells[0].Value + "," + row.Cells[2].Value + "," + row.Cells[4].Value);
DetectorCardTypeData.Add(CurrentRowData);
}
StringCollection TestData = new StringCollection();
foreach (string CardData in DetectorCardTypeData)
{
TestData.Add(CardData);
}
//Configuration config = ConfigurationManager.OpenExeConfiguration(Application.ExecutablePath);
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
ConfigurationSectionGroup applicationSectionGroup = config.GetSectionGroup("applicationSettings");
ConfigurationSection applicationConfigSection = applicationSectionGroup.Sections["EXP_Battery_Calculator.Properties.Settings"];
ClientSettingsSection clientSection = (ClientSettingsSection)applicationConfigSection;
SettingElement appData = clientSection.Settings.Get("Test");
foreach (string WriteME in TestData)
{
appData.Value.ValueXml.InnerText = WriteME;
clientSection.Settings.Add(appData);
}
applicationConfigSection.SectionInformation.ForceSave = true;
config.Save();
listBox1.DataSource = TestData;
}
Still can't understand why need to store data in the application config, but anyway.
First of all, create a new parameter in your Settings file. Name it as you want ("StoredData" in example below), set type to System.Collections.Specialized.StringCollections
, set scope "Application" and add default value (i've added "Empty"). This should produce an XML string:
<?xml version="1.0" encoding="utf-16"?>
<ArrayOfString xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<string>Empty</string>
</ArrayOfString>
and also will modify default config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="YourNamespace.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
<applicationSettings>
<YourNamespace.Properties.Settings>
<setting name="StoredData" serializeAs="Xml">
<value>
<ArrayOfString xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<string>Empty</string>
</ArrayOfString>
</value>
</setting>
</YourNamespace.Properties.Settings>
</applicationSettings>
</configuration>
To edit ArrayOfString
node i've used this code:
// Diving through config nodes to <value> element
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var appSettings = config.SectionGroups.Get("applicationSettings");
if (appSettings == null)
return;
var settingsSection = appSettings.Sections.OfType<ClientSettingsSection>()
.FirstOrDefault(section => section.Settings.Get(nameof(Properties.Settings.Default.StoredData)) != null);
if (settingsSection == null)
return;
var storedData = settingsSection.Settings.Get(nameof(Properties.Settings.Default.StoredData))?.Value?.ValueXml;
if (storedData == null)
return;
// Removing everyting from <ArrayOfString> (including it)
storedData.RemoveAll();
// Initializing XmlDocument instance to create new nodes
var xDoc = new XmlDocument();
// Manually creating parent node <ArrayOfString xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
var xArrayOfString = xDoc.CreateElement("ArrayOfString");
xArrayOfString.SetAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
xArrayOfString.SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
// Just test collection of strings
var testData = Enumerable.Range(0, 15).Select(x => x.ToString());
// Looping through records of DataGridView, which should already been "stringified"
// Creating nodes <string>...</string> where "..." is string representation of each DataGridView row (in a way to want to store it)
foreach (var testDataItem in testData)
{
var xString = xDoc.CreateElement("string");
xString.InnerText = testDataItem;
xArrayOfString.AppendChild(xString);
}
// And appending new rebuilded <ArrayOfString> to a <value> node in config
storedData.AppendChild(storedData.OwnerDocument.ImportNode(xArrayOfString, true));
// And just saving
config.Save(ConfigurationSaveMode.Minimal, true);
That example, after config.Save
call immediately rewrites config and produces such look:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="YourNamespace.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
<applicationSettings>
<YourNamespace.Properties.Settings>
<setting name="StoredData" serializeAs="Xml">
<value>
<ArrayOfString xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<string>0</string>
<string>1</string>
<string>2</string>
<string>3</string>
<string>4</string>
<string>5</string>
<string>6</string>
<string>7</string>
<string>8</string>
<string>9</string>
</ArrayOfString>
</value>
</setting>
</YourNamespace.Properties.Settings>
</applicationSettings>
</configuration>
BUT it doesn't updates Property.Settings.Default.StoredData
property at runtime. Only after application restart it will load modified data from config. It also doesn't modifies "App.config" in your project folder. Only "YourAssemblyName.exe.config" near your output binary file.
Not sure this way is appropriate or applicable. Still didn't understand why you decided to punish little config file in such way. You have user-scoped settings for that. Or just write own separate file such as "myStoredData.xml" in application directory.