In my project I have a custom struct:
struct Point {
public uint xPoint { get; }
public uint yPoint { get; }
public Point(uint x, uint y) {
xPoint = x;
yPoint = y;
}
}
I'm using a list of these Points:
List<Point> pathToNavigate = new List<Point>();
What I'm trying to do is save a list of my Points to the Settings.settings:
I can't figure out how to change string to be a list of my struct Point.
I tried messing with the xml and manually add in my option but I can't work out how to do it. Most things I find tell me to use a custom namespace but I also can't get that working with a list of my Point struct.
Edit: My problem is with a custom struct using a list. The issue isn't adding the items to the list, it's being able to load their contents properly.
Applying the duplicate to your case (I can't flag it because I can't revote to close, and I post this answer to solve your difficulties as well as to be more precise and more complete than the various tutorials and duplicates):
How to save a List<string> on Settings.Default?
Having the serializable struct in for example the namespace below:
namespace WindowsFormsAppTest
{
[Serializable]
public struct Point
{
public uint xPoint { get; set; }
public uint yPoint { get; set; }
public Point(uint x, uint y)
{
xPoint = x;
yPoint = y;
}
}
}
As mentionned previously, properties must be read-write, so I added auto-setters, and the struct must be serializable by adding the attrribute.
Compile the project.
You need to create a string parameter for example having the name MyList
:
Then edit Settings.settings
by hand using any text editor to change its type to:
System.Collections.Generic<WindowsFormsAppTest.Point>
In HTML text encoding like:
System.Collections.Generic.List<WindowsFormsAppTest.Point>
Settings.settings
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="WindowsFormsAppTest.Properties" GeneratedClassName="Settings">
<Profiles />
<Settings>
<Setting Name="MyList" Type="System.Collections.Generic.List<WindowsFormsAppTest.Point>" Scope="User">
<Value Profile="(Default)" />
</Setting>
</Settings>
</SettingsFile>
After saved, go to Visual Studio and reload the file, then you will be able to see the type is changed:
You need to update this settings generated C# code file using the designer by expanding the type of the parameter and to click on this custom list type:
If not, or in case of problem, you need to manually update these file:
app.config to serializeAs Xml
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="WindowsFormsAppTest.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/></startup>
<userSettings>
<WindowsFormsAppTest.Properties.Settings>
<setting name="MyList" serializeAs="Xml">
<value />
</setting>
</WindowsFormsAppTest.Properties.Settings>
</userSettings>
</configuration>
Settings.Designer.cs to change the type of the property
public global::System.Collections.Generic.List<WindowsFormsAppTest.Point> MyList {
get {
return ((global::System.Collections.Generic.List<WindowsFormsAppTest.Point>)(this["MyList"]));
}
Save all and/or compile again.
Now, you can write for example in the Main
method or in the constructor of the main form or in the load event handler:
private void FormTest_Load(object sender, EventArgs e)
{
if ( Properties.Settings.Default.MyList == null )
Properties.Settings.Default.MyList = new List<Point>();
Properties.Settings.Default.Save();
}
And for example in a button click event handler:
private void ButtonCreate_Click(object sender, EventArgs e)
{
Properties.Settings.Default.MyList.Add(new Point(10, 10));
Properties.Settings.Default.MyList.Add(new Point(10, 20));
Properties.Settings.Default.MyList.Add(new Point(20, 20));
Properties.Settings.Default.MyList.Add(new Point(50, 50));
Properties.Settings.Default.Save();
}
Now the config file is:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<userSettings>
<WindowsFormsAppTest.Properties.Settings>
<setting name="MyList" serializeAs="Xml">
<value>
<ArrayOfPoint xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Point>
<xPoint>10</xPoint>
<yPoint>10</yPoint>
</Point>
<Point>
<xPoint>10</xPoint>
<yPoint>20</yPoint>
</Point>
<Point>
<xPoint>20</xPoint>
<yPoint>20</yPoint>
</Point>
<Point>
<xPoint>50</xPoint>
<yPoint>50</yPoint>
</Point>
</ArrayOfPoint>
</value>
</setting>
</WindowsFormsAppTest.Properties.Settings>
</userSettings>
</configuration>
To change one item we can write, because being a struct so a value-type:
private void ButtonUpdate_Click(object sender, EventArgs e)
{
var point = Properties.Settings.Default.MyList[0];
point.xPoint = 100;
point.yPoint = 100;
Properties.Settings.Default.MyList[0] = point;
Properties.Settings.Default.Save();
}
And now the settings file has:
<Point>
<xPoint>100</xPoint>
<yPoint>100</yPoint>
</Point>
...
To test this, we can list the items using another button:
private void ButtonShow_Click(object sender, EventArgs e)
{
var list = Properties.Settings.Default.MyList.Select(p => $"{p.xPoint}, {p.yPoint}");
MessageBox.Show(string.Join(Environment.NewLine, list.ToArray()));
}
Note
To cleanup the application settings, you need to delete for example all these folders:
c:\Users\User\AppData\Local\Organization\WindowsFormsAppTest.exe_Url_*
Where Organization
and WindowsFormsAppTest
comes from the manifest file defined in AssemblyInfo.cs
using fields AssemblyCompany
and AssemblyTitle
.
The steps below work.
However, I believe your issue is simply because xPoint
and yPoint
do not have public setters. This is due to how XmlSerializer
works. See the documentation here .
First, create a setting. In this case I named it ListOfPoints
. The type is irrelevant, we're going to change it anyways.
Manually edit "Settings.settings". I just open it with Visual Studio's XML editor but use what you prefer.
Then change the type of the setting only. Note you need to use HTML encoding for <
and >
.
Entire Settings.settings:
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="WindowsFormsApp1.Properties" GeneratedClassName="Settings">
<Profiles />
<Settings>
<Setting Name="ListOfPoints" Type="System.Collections.Generic.List<WindowsFormsApp1.MyPoint>" Scope="User">
<Value Profile="(Default)" />
</Setting>
</Settings>
</SettingsFile>
The only change made was this:
Type="System.Collections.Generic.List<WindowsFormsApp1.MyPoint>"
All Code:
[Serializable]
public struct MyPoint
{
public uint X { get; set; }
public uint Y { get; set; }
public MyPoint(uint x, uint y)
{
X = x;
Y = y;
}
public override bool Equals(object obj)
{
if (!(obj is MyPoint))
return false;
var other = (MyPoint)obj;
return other.X == X && other.Y == Y;
}
public override int GetHashCode()
{
return unchecked(X.GetHashCode() ^ Y.GetHashCode());
}
}
private static readonly List<MyPoint> saveMe = new List<MyPoint>();
private static List<MyPoint> loadMe;
private static void SaveData()
{
Properties.Settings.Default.ListOfPoints = saveMe;
Properties.Settings.Default.Save();
}
private static void LoadData()
{
Properties.Settings.Default.Reload();
loadMe = Properties.Settings.Default.ListOfPoints;
TestData();
}
private static void TestData()
{
if (loadMe.Count != saveMe.Count)
throw new Exception("Different counts");
for (int i = 0; i < loadMe.Count; i++)
{
if (!loadMe[i].Equals(saveMe[i]))
throw new Exception($"{nameof(MyPoint)} at index {i} doesn't match");
}
}
Test this by adding whatever you wish to saveMe
. Then run SaveData
followed by LoadData
.
LoadData
will throw an exception if the data doesn't match.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.