Saving simple user preferences on Windows Forms with C# - c#

I'm writing my first Windows Forms application using VS 2010 and C#. It does not use a database but I would like to save user settings like directory path and what check boxes are checked. What is the easiest way to save these preferences?

I suggest you to use the builtin application Settings to do it. Here is an article talking about it.
Sample usage:
MyProject.Properties.Settings.Default.MyProperty = "Something";

You can use the serializable attribute in conjunction with a 'settings' class. For small amount of information this is really your best bet as it is simple to implement. For example:
[Serializable]
public class MySettings
{
public const string Extension = ".testInfo";
[XmlElement]
public string GUID { get; set; }
[XmlElement]
public bool TurnedOn { get; set; }
[XmlElement]
public DateTime StartTime { get; set; }
public void Save(string filePath)
{
XmlSerializer serializer = new XmlSerializer(typeof(MySettings));
TextWriter textWriter = new StreamWriter(filePath);
serializer.Serialize(textWriter, this);
textWriter.Close();
}
public static MySettings Load(string filePath)
{
XmlSerializer serializer = new XmlSerializer(typeof(MySettings));
TextReader reader = new StreamReader(filePath);
MySettings data = (MySettings)serializer.Deserialize(reader);
reader.Close();
return data;
}
}
There you go. You can prety much cut and paste this directly into your code. Just add properties as needed, and don't forget the [XMLElement] attribute on your interesting properties.
Another benefit to this design is that you don't have to fiddle with the cumbersome Application.Settings approaches, and you can modify your files by hand if you need to.

I'd save the settings in an XML file. That way it's easy for the user to share their settings across machines etc.
You'll also be able to deserialize the XML as a class in your application, giving you easy access to the settings you require.

The easiest way would be in the app.config settings which you can set in the designer under project properties settings (make sure you set them as user setting not application settings or you wont be able to save them) you can then read and write them with C#
to read write just access properties on
Properties.Settings.Default.<your property>
there are also methods to save the properties to the users profile or to reset to defaults
Properties.Settings.Default.Reset();
Properties.Settings.Default.Save();
http://msdn.microsoft.com/en-us/library/a65txexh.aspx

What about adding a local dataset to your project (then create a setting table) and export the data finally to an xml file, its easy to use and more fixable
1- add columns (e.g.; settingName and settingValue) to your local table (DataTable1) using the designer,
then
//data set
DataSet1 ds = new DataSet1();
DataSet1.DataTable1DataTable settingsTable = (DataSet1.DataTable1DataTable)ds.Tables[0];
//add new setting
settingsTable.Rows.Add(new string[] { "setting1", "settingvalue1" });
//export to xml file
settingsTable.WriteXml("settings.xml");
//if you want to read ur settings back... read from xml
settingsTable.ReadXml("settings.xml");

Related

C# deserialize a class - the "default" value of a variable

I save local user settings to xml file. Program contains "Settings" class that serialize when the program is closed and deserialize when it is started next time.
But the problem is that the program is changed all the time, and when I create next version - I want the user settings to be saved. But the program may contains new fields of settings, and then the program will started and deserialised the old xml file - new fields will be null.
Now I check every fields as hard-code in the program, as like:
Settings sts = (Settings)Deserialise(path);
if(sts.Field2 == null) sts.Field2 = "defaultvalue2";
if(sts.Field3 == null) sts.Field3 = "defaultvalue3";
Of course it is not satisfied for me. Is it possible to do "default" value of a variable as the same time when I change code of Settings class? Like this:
class Settings
{
public string Field1 (DefaultValue: "defaultvalue1");
public string Field2 (DefaultValue: "defaultvalue2");
}
public void Main
{
Settings sts = (Settings)Deserialise(path);
foreach(var fld in typeof(sts))
{
if(fld.Value == null)
fld.Value = Settings.Fields[fld].DefaulValue;
}
}
Yes it is possible, simply use the standard way to set standard values:
class Settings
{
public string Field1 = "defaultvalue1";
public string Field2 = "defaultvalue2";
}
public void Main
{
Settings sts = (Settings)Deserialise(path);
/* not needed
foreach(var fld in typeof(sts))
{
if(fld.Value == null)
fld.Value = Settings.Fields[fld].DefaulValue;
}*/
}
https://learn.microsoft.com/zh-tw/dotnet/api/system.xml.serialization.xmlattributes.xmldefaultvalue?view=netcore-3.1
here I google it . maybe try it?
Use default attribute : DefaultValueAttribute
public class Pet
{
// The default value for the Animal field is "Dog".
[DefaultValueAttribute("Dog")]
public string Animal ;
}
The Settings.settings xml file was designed for static project settings and, using user scoped settings, can be saved at runtime. Are you changing the settings so much that it no longer have the 'old' values or just adding to the list of settings?
If just adding, you don't need to loop through the settings one by one and try to guess their types with values as you can just do this:
int myInteger = Properties.Settings.Default.MyIntegerSettingValue;
And writing to the settings file:
Properties.Settings.Default.MyIntegerSettingValue = myInteger;
So if you cannot replace your settings.xml file, my suggestion is to model your settings to a class that contain all of your settings loaded at runtime and for each one missing, just write it out to the Settings file with your default value:
Properties.Settings.Default.MyMissingSetting = "MyDefaultValue"
You can find some nice info on application settings usage here

Is there a way to read and convert a language config file into an object?

I wanted to add language support into my new project. I thought of creating a config file, similar to json.
So this is an example file:
{
"LabelTextMainMenu": "This is the main Label",
"LabelTextName": "Please enter your name"
}
Now what I want to reach is this (Classname not existing):
LangConfig config = File.ReadAllText(path/to/language/config);
public string LabelName
{
get {config.LabelTextName}
}
Before I'd write this "LangConfig"-Class myself, i'd like to know if there's something that works in the way I want it?
You can deserialize the config file to typed object via Json.Net (or equivalent package).
Below is the sample implementation :
var configData = File.ReadAllText(path/to/language/config.config);
LangConfig config = JsonConvert.DeserializeObject<LangConfig>(configData);
with the typed object, the properties can be accessed as
public string LabelName
{
get {config.LabelTextName}
}

Remove metadata from Excel file using C#?

I'm currently using C# to set the custom attributes of multiple excel files. I'm using an imported library from Microsoft known as DSOFile to write to the CustomProperties property. One issue that I'm running into is whenever the code attempts to write to an excel file that already has custom properties written to it, such as the Company and Year, a COMException exception is thrown to indicate the custom properties of the file already has a field with that name. Exact Message: "An item by that name already exists in the collection". I would like to be able to delete that item in the collection so that I can rewrite to the file. For example, if I accidentally added the wrong year to the year attribute in the file, I would like the ability to clear that field and write a new value to it. I was unable to find a method in the DSOFile class that removes metadata. Is there anyway to "programmatically" clear metadata from a file without doing it through the file properties window?
Sample Code:
DSOFILE.OleDocumentProperties dso = new DSOFile.OleDocumentProperties();
dso.Open(#"c\temp\test.xls", false, DSOFile.dsoFileOpenOptions.dsoOptionDefault);
//add metadata
dso.CustomProperties.Add("Company", "Sony");
dso.Save();
dso.Close(false);
If you want to change the default properties used by Office like Company or Author, you can just update them via the SummaryProperties object:
OleDocumentProperties dso = new DSOFile.OleDocumentProperties();
dso.Open(#"c:\temp\test.xls", false, DSOFile.dsoFileOpenOptions.dsoOptionDefault);
//Update Company
dso.SummaryProperties.Company = "Hello World!";
dso.Save();
dso.Close(false);
Note, that you cannot change the default properties of documents that you can access via the SummaryProperties object via the CustomProperties object in dso. The CustomProperties are meant for additional properties used by the user, not the ones already introduced by Microsoft Office.
In order to change the custom properties, you have to be aware that CustomProperties is a collection that you can iterate over via foreach. So you can use the following two methods:
private static void DeleteProperty(CustomProperties properties, string propertyName)
{
foreach(CustomProperty property in properties)
{
if (string.Equals(property.Name, propertyName, StringComparison.InvariantCultureIgnoreCase))
{
property.Remove();
break;
}
}
}
private static void UpdateProperty(CustomProperties properties, string propertyName, string newValue)
{
bool propertyFound = false;
foreach (CustomProperty property in properties)
{
if (string.Equals(property.Name, propertyName, StringComparison.InvariantCultureIgnoreCase))
{
// Property found, change it
property.set_Value(newValue);
propertyFound = true;
break;
}
}
if(!propertyFound)
{
// The property with the given name was not found, so we have to add it
properties.Add(propertyName, newValue);
}
}
Here is an example on how to use UpdateProperty:
static void Main(string[] args)
{
OleDocumentProperties dso = new DSOFile.OleDocumentProperties();
dso.Open(#"c:\temp\test.xls", false, DSOFile.dsoFileOpenOptions.dsoOptionDefault);
UpdateProperty(dso.CustomProperties, "Year", "2017");
dso.Save();
dso.Close(false);
}

Changing ResourceManager (Make it Updatable)

I have a project in MVC 3 (Razor) For localization we are using Strongly typed resources.
We want to have possibility to update translation that already exist "on-line". It means, that it should be possible to edit translation on the website. (e.g. If in the url there is parameter like "translateLanguage=on") Basically, it is not possible to do that with current solution, because if resource has been changed, then it must be recompiled.
Of course we can write our own Resource Manager that will be using a database, but then we would have to rewrite all of our translations to the database and that would be time consuming. It would also mean that we would have to change all of our code to reflect this "new" resource manager.
It would be hard to implement it in all things. Now, we can use it in attributes
e.g.
[Required(ErrorMessageResourceType = typeof(_SomeResource), ErrorMessageResourceName = "SomeResouceElement")
SomeProperty
As well as in code:
string translatedResource = _SomeResource.SomeResourceElement;
Could you provide me with some information how to do this in mvc 3?
Generally resource file consists of two parts xml + autogenerated cs code. If you open resource designer file you will see
/// <summary>
/// Looks up a localized string similar to About project.
/// </summary>
public static string about_project {
get {
return ResourceManager.GetString("about_project", resourceCulture);
}
}
So what you can do you can use ResourceManager.GetString("Key")
Thread.CurrentThread.CurrentCulture = new CultureInfo(cultureName);
var t = Resources.ResourceManager.GetResourceSet(new CultureInfo(cultureName), true, true);
To make it more smart you can rewrite BaseView
public abstract class ViewBase<TModel> : System.Web.Mvc.WebViewPage<TModel>
{
public string GetTranslation(string key)
{
return _rManager.GetString(key);
}
private ResourceManager _rManager;
protected ViewBase()
{
_rManager = Resources.ResourceManager.GetResourceSet(new CultureInfo(cultureName), true, true);
}
}
And then you will be able to use GetTranslation in your razor view (To run this base view you need to modify web.config from Views folder)
And then you will be able after editing xml access to resource data.

Storing key/value pairs on disk using WPF

I have a bunch of key/value pairs I'd like to cache for my WPF application. In Silverlight this is deliciously easy - I can just do:
IsolatedStorageSettings userSettings = IsolatedStorageSettings.ApplicationSettings;
wombat = (string)userSettings["marsupial"];
Is there anything like this in WPF? A wombat may not be a marsupial, now I think about it. Some work needed there.
Edit: I would like if I can to avoid serialising these to/from en masse, as there are going to be a very large number of them with large amounts of data in them (I'm caching web pages).
The IsolatedStorageSettings doesn't exist in the desktop version of the .NET Framework, it's only available in Silverlight. However you can use IsolatedStorage in any .NET application; just serialize a Dictionary<string, object> to a file in isolated storage.
var settings = new Dictionary<string, object>();
settings.Add("marsupial", wombat);
BinaryFormatter formatter = new BinaryFormatter();
var store = IsolatedStorageFile.GetUserStoreForAssembly();
// Save
using (var stream = store.OpenFile("settings.cfg", FileMode.OpenOrCreate, FileAccess.Write))
{
formatter.Serialize(stream, settings);
}
// Load
using (var stream = store.OpenFile("settings.cfg", FileMode.OpenOrCreate, FileAccess.Read))
{
settings = (Dictionary<string, object>)formatter.Deserialize(stream);
}
wombat = (string)settings["marsupial"];
If by WPF, you mean the full .Net runtime, then yes. There's a default Settings class created with the WPF project template.
Settings class
See this discussion
It doesn't exist in WPF but can easily be ported from Mono's moonlight implementation (http://vega.frugalware.org/tmpgit/moon/class/System.Windows/System.IO.IsolatedStorage/IsolatedStorageSettings.cs)
//Modifications at MoonLight's IsolatedStorageSettings.cs to make it work with WPF (whether deployed via ClickOnce or not):
// per application, per-computer, per-user
public static IsolatedStorageSettings ApplicationSettings {
get {
if (application_settings == null) {
application_settings = new IsolatedStorageSettings (
(System.Threading.Thread.GetDomain().ActivationContext!=null)?
IsolatedStorageFile.GetUserStoreForApplication() : //for WPF, apps deployed via ClickOnce will have a non-null ActivationContext
IsolatedStorageFile.GetUserStoreForAssembly());
}
return application_settings;
}
}
// per domain, per-computer, per-user
public static IsolatedStorageSettings SiteSettings {
get {
if (site_settings == null) {
site_settings = new IsolatedStorageSettings (
(System.Threading.Thread.GetDomain().ActivationContext!=null)?
IsolatedStorageFile.GetUserStoreForApplication() : //for WPF, apps deployed via ClickOnce will have a non-null ActivationContext
IsolatedStorageFile.GetUserStoreForAssembly());
//IsolatedStorageFile.GetUserStoreForSite() works only for Silverlight applications
}
return site_settings;
}
}
Note that you should also change the #if block at the top of that code to write
if !SILVERLIGHT
Also take a look at this for custom settings storage

Categories