It seems the question should really be phrased like this:
How can I define default values when I use a custom type in my project's Properties\Settings.setting definitions?
Per comments to the original version of this answer, it seems the XML shown in the question is not really relevant - what's really important is that default values get populated.
(Of course, correct me if I'm wrong, OP.)
Step 1: Define a custom type
Any class will do. But it must have a parameterless constructor. For this example, I just made a Part
class with three string properties.
Step 2: Create a TypeConverter for the custom type
This allows the underlying .NET classes to convert a string into this custom type.
This is the 'magic' step, because any default value entered into the Settings designer is always auto-generated as a string
parameter to a DefaultSettingValueAttribute
.
(The core idea for this came from another SO answer here.)
And don't forget to attribute the class from Step 1 with this converter.
Step 3: Create a setting that uses the custom type
In the Settings designer window, when selecting a Type, choose 'Browse...'. In the window that appears, you won't be able to find your type in the main GUI tree. That's OK; just type the fully qualified type name (with all of its namespaces) into the text field. (In this example, it's SomeNamespace.Part
.)
After opening the Type drop-down and selecting Browse:
Then enter a default string in the Value column which your TypeConverter from Step 2 can convert to your custom Type from Step 1. I chose a;b;c
.
Putting it all together:
You can use this code sample, together with the instructions above, to test the idea. It will ensure your custom settings type has default values. Parts of the TypeConverter code lines are taken from the answer linked above.
using System;
using System.ComponentModel;
namespace SomeNamespace
{
public class Program
{
static void Main()
{
Part p = Properties.Settings.Default.Part;
// you can breakpoint here after deleting user.config, and verify that p contains default values.
p.display_name = "Extra 3";
p.work_name = "Sonstiges3";
p.folder_path = "path";
Properties.Settings.Default.Part = p;
Properties.Settings.Default.Save();
}
}
[TypeConverter(typeof(PartConverter))]
public class Part
{
public string display_name { get; set; }
public string work_name { get; set; }
public string folder_path { get; set; }
// parameterless constructor required for using as a custom Settings object
public Part() { }
// used with the TypeConverter to go back-and-forth between class type and string
public override string ToString()
{
return $"{display_name};{work_name};{folder_path}";
}
}
public class PartConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value is string stringValue && !string.IsNullOrWhiteSpace(stringValue))
{
// Obviously, using more robust parsing in production code is recommended.
string[] parts = stringValue.Split(';');
if (parts.Length == 3)
return new Part() { display_name = parts[0], work_name = parts[1], folder_path = parts[2] };
else
throw new FormatException("Invalid format");
}
else
return base.ConvertFrom(context, culture, value);
}
}
}
For completeness, here's the auto-generated designer code. Note how the default value of a;b;c
is generated:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace SomeNamespace.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.7.0.0")]
public sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("a;b;c")]
public global::SomeNamespace.Part Part {
get {
return ((global::SomeNamespace.Part)(this["Part"]));
}
set {
this["Part"] = value;
}
}
}
}