I'm trying to save the following classes using a custom Settings Provider but keep getting a null reference error (error details below).
[Serializable]
public class SoundClips
{
[System.Xml.Serialization.XmlElementAttribute("Items")]
public List<SoundKeyBind> Items { get; set; }
public SoundClips()
{
Items = new List<SoundKeyBind>();
}
}
[Serializable]
public class SoundKeyBind
{
public string FilePath { get; set; }
public string FileName { get; set; }
public string KeyBindText { get; set; }
public KeyPressedEventArgs KeyBind { get; set; }
}
Saved by:
dgvSoundBoard.DataSource = keyBinds.Items;
Properties.Settings.Default.SoundBinds = keyBinds;
Properties.Settings.Default.Save();
I got the following Settings Provider on GitHub somewhere but can't find the link to reference it, sorry.
public sealed class MySettingsProvider : SettingsProvider, IApplicationSettingsProvider
{
private const string _rootNodeName = "settings";
private const string _localSettingsNodeName = "localSettings";
private const string _globalSettingsNodeName = "globalSettings";
private const string _className = "MySettingsProvider";
private XmlDocument _xmlDocument;
private string _filePath
{
get
{
return Path.Combine(Path.GetDirectoryName(Application.ExecutablePath),
string.Format("{0}.settings", ApplicationName));
}
}
private XmlNode _localSettingsNode
{
get
{
XmlNode settingsNode = GetSettingsNode(_localSettingsNodeName);
XmlNode machineNode = settingsNode.SelectSingleNode(Environment.MachineName.ToLowerInvariant());
if (machineNode == null)
{
machineNode = _rootDocument.CreateElement(Environment.MachineName.ToLowerInvariant());
settingsNode.AppendChild(machineNode);
}
return machineNode;
}
}
private XmlNode _globalSettingsNode
{
get { return GetSettingsNode(_globalSettingsNodeName); }
}
private XmlNode _rootNode
{
get { return _rootDocument.SelectSingleNode(_rootNodeName); }
}
private XmlDocument _rootDocument
{
get
{
if (_xmlDocument == null)
{
try
{
_xmlDocument = new XmlDocument();
_xmlDocument.Load(_filePath);
}
catch (Exception)
{
}
if (_xmlDocument.SelectSingleNode(_rootNodeName) != null)
return _xmlDocument;
_xmlDocument = GetBlankXmlDocument();
}
return _xmlDocument;
}
}
public override string ApplicationName
{
get { return Path.GetFileNameWithoutExtension(Application.ExecutablePath); }
set { }
}
public override string Name
{
get { return _className; }
}
public override void Initialize(string name, NameValueCollection config)
{
base.Initialize(Name, config);
}
public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection)
{
foreach (SettingsPropertyValue propertyValue in collection)
SetValue(propertyValue);
try
{
_rootDocument.Save(_filePath);
}
catch (Exception)
{
/*
* If this is a portable application and the device has been
* removed then this will fail, so don't do anything. It's
* probably better for the application to stop saving settings
* rather than just crashing outright. Probably.
*/
}
}
public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection)
{
SettingsPropertyValueCollection values = new SettingsPropertyValueCollection();
foreach (SettingsProperty property in collection)
{
values.Add(new SettingsPropertyValue(property)
{
SerializedValue = GetValue(property)
});
}
return values;
}
private void SetValue(SettingsPropertyValue propertyValue)
{
XmlNode targetNode = IsGlobal(propertyValue.Property)
? _globalSettingsNode
: _localSettingsNode;
XmlNode settingNode = targetNode.SelectSingleNode(string.Format("setting[#name='{0}']", propertyValue.Name));
if (settingNode != null)
settingNode.InnerText = propertyValue.SerializedValue.ToString();
else
{
settingNode = _rootDocument.CreateElement("setting");
XmlAttribute nameAttribute = _rootDocument.CreateAttribute("name");
nameAttribute.Value = propertyValue.Name;
settingNode.Attributes.Append(nameAttribute);
// ######### ERROR OCCURS HERE #########
settingNode.InnerText = propertyValue.SerializedValue.ToString();
// ######### ERROR OCCURS HERE #########
targetNode.AppendChild(settingNode);
}
}
private string GetValue(SettingsProperty property)
{
XmlNode targetNode = IsGlobal(property) ? _globalSettingsNode : _localSettingsNode;
XmlNode settingNode = targetNode.SelectSingleNode(string.Format("setting[#name='{0}']", property.Name));
if (settingNode == null)
return property.DefaultValue != null ? property.DefaultValue.ToString() : string.Empty;
return settingNode.InnerText;
}
private bool IsGlobal(SettingsProperty property)
{
foreach (DictionaryEntry attribute in property.Attributes)
{
if ((Attribute)attribute.Value is SettingsManageabilityAttribute)
return true;
}
return false;
}
private XmlNode GetSettingsNode(string name)
{
XmlNode settingsNode = _rootNode.SelectSingleNode(name);
if (settingsNode == null)
{
settingsNode = _rootDocument.CreateElement(name);
_rootNode.AppendChild(settingsNode);
}
return settingsNode;
}
public XmlDocument GetBlankXmlDocument()
{
XmlDocument blankXmlDocument = new XmlDocument();
blankXmlDocument.AppendChild(blankXmlDocument.CreateXmlDeclaration("1.0", "utf-8", string.Empty));
blankXmlDocument.AppendChild(blankXmlDocument.CreateElement(_rootNodeName));
return blankXmlDocument;
}
public void Reset(SettingsContext context)
{
_localSettingsNode.RemoveAll();
_globalSettingsNode.RemoveAll();
_xmlDocument.Save(_filePath);
}
public SettingsPropertyValue GetPreviousVersion(SettingsContext context, SettingsProperty property)
{
// do nothing
return new SettingsPropertyValue(property);
}
public void Upgrade(SettingsContext context, SettingsPropertyCollection properties)
{
}
}
The error occurs in the Settings Provider, in private void SetValue(SettingsPropertyValue propertyValue) when it tries to access propertyValue.SerializedValue.ToString() which is null. I have commented around it in the code above to help highlight the location. The error is:
An unhandled exception of type 'System.NullReferenceException' occurred in SoundBoard.exe
Object reference not set to an instance of an object.
In the settings designer I have set the Provider of the setting to MySettingsProvider and set Roaming to True. I'm guessing that I've got something wrong with the Serialization declaration for the classes, but I've tried a few things, for example:
[Serializable]
[SettingsSerializeAs(SettingsSerializeAs.Xml)]
public class SoundClips
and can't figure it out.
Any help would be greatly appreciated.
I managed to solve the problem by breaking the class down and saving each bit one at a time. The problem turned out to be that the SoundKeyBind class and the KeyPressedEventArgs class/object which was created within it required a constructor which takes no parameters.
I.e. I needed to add the following to the respective classes:
public SoundKeyBind() { }
and
public KeyPressedEventArgs() { }
Related
I'm trying to save some custom classes in XML format using a custom SettingsProvider which I found on GitHub (sorry but I can't find the link). But the output has special characters (E.g. <) converted (see below). The classes I'm trying to save are as follows:
[Serializable]
public class SoundClips
{
//[System.Xml.Serialization.XmlElementAttribute("Items")]
public List<SoundKeyBind> Items { get; set; }
public SoundClips()
{
Items = new List<SoundKeyBind>();
}
}
[Serializable]
public class SoundKeyBind
{
//[System.Xml.Serialization.XmlElementAttribute("FilePath")]
public string FilePath { get; set; }
//[System.Xml.Serialization.XmlElementAttribute("FileName")]
public string FileName { get; set; }
//[System.Xml.Serialization.XmlElementAttribute("Volume")]
public float Volume { get; set; }
//[System.Xml.Serialization.XmlElementAttribute("KeyBindText")]
public string KeyBindText { get; set; }
//[System.Xml.Serialization.XmlElementAttribute("KeyBind")]
public KeyPressedEventArgs KeyBind { get; set; }
public SoundKeyBind (string FilePath, string FileName, float Volume, string KeyBindText, KeyPressedEventArgs KeyBind)
{
this.FilePath = FilePath;
this.FileName = FileName;
this.Volume = Volume;
this.KeyBindText = KeyBindText;
this.KeyBind = KeyBind;
}
public SoundKeyBind() { } //Required for serialization to work
}
[Serializable]
public class KeyPressedEventArgs : EventArgs
{
//[System.Xml.Serialization.XmlElementAttribute("Modifier")]
public uint Modifier { get; set; }
//[System.Xml.Serialization.XmlElementAttribute("Keys")]
public Keys Key { get; set; }
public KeyPressedEventArgs(uint modifier, Keys key)
{
this.Modifier = modifier;
this.Key = key;
}
public KeyPressedEventArgs() { } //Required for serialization to work
}
The setting is configured as follows in the Settings Designer:
Name = "SoundBinds"
Provider = "MySettingsProvider"
Roaming = "True"
Scope = "User"
SettingTypeName="Sound_Board.SoundClips"
I'm saving the values like this:
class SharedVars
{
//Excess code removed
public static SoundClips keyBinds = new SoundClips(); //Stores key bind and sound file info
}
//Then elsewhere in the form
SharedVars.keyBinds.Items.Add(new SoundKeyBind("D:\\Sounds\\Example.mp3", "Example.mp3", 0.5f, "Shift + A", new KeyPressedEventArgs(4, Keys.A))); //Add an example key bind
Properties.Settings.Default.SoundBinds = SharedVars.keyBinds;
Properties.Settings.Default.Save();
Here is the custom SettingsProvider:
namespace Sound_Board
{
public sealed class MySettingsProvider : SettingsProvider, IApplicationSettingsProvider
{
private const string _rootNodeName = "settings";
private const string _localSettingsNodeName = "localSettings";
private const string _globalSettingsNodeName = "globalSettings";
private const string _className = "MySettingsProvider";
private XmlDocument _xmlDocument;
private string _filePath
{
get
{
return Path.Combine(Path.GetDirectoryName(Application.ExecutablePath),
string.Format("{0}.settings", ApplicationName));
}
}
private XmlNode _localSettingsNode
{
get
{
XmlNode settingsNode = GetSettingsNode(_localSettingsNodeName);
XmlNode machineNode = settingsNode.SelectSingleNode(Environment.MachineName.ToLowerInvariant());
if (machineNode == null)
{
machineNode = _rootDocument.CreateElement(Environment.MachineName.ToLowerInvariant());
settingsNode.AppendChild(machineNode);
}
return machineNode;
}
}
private XmlNode _globalSettingsNode
{
get { return GetSettingsNode(_globalSettingsNodeName); }
}
private XmlNode _rootNode
{
get { return _rootDocument.SelectSingleNode(_rootNodeName); }
}
private XmlDocument _rootDocument
{
get
{
if (_xmlDocument == null)
{
try
{
_xmlDocument = new XmlDocument();
_xmlDocument.Load(_filePath);
}
catch (Exception)
{
}
if (_xmlDocument.SelectSingleNode(_rootNodeName) != null)
return _xmlDocument;
_xmlDocument = GetBlankXmlDocument();
}
return _xmlDocument;
}
}
public override string ApplicationName
{
get { return Path.GetFileNameWithoutExtension(Application.ExecutablePath); }
set { }
}
public override string Name
{
get { return _className; }
}
public override void Initialize(string name, NameValueCollection config)
{
base.Initialize(Name, config);
}
public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection)
{
foreach (SettingsPropertyValue propertyValue in collection)
SetValue(propertyValue);
try
{
_rootDocument.Save(_filePath);
}
catch (Exception)
{
/*
* If this is a portable application and the device has been
* removed then this will fail, so don't do anything. It's
* probably better for the application to stop saving settings
* rather than just crashing outright. Probably.
*/
}
}
public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection)
{
SettingsPropertyValueCollection values = new SettingsPropertyValueCollection();
foreach (SettingsProperty property in collection)
{
values.Add(new SettingsPropertyValue(property)
{
SerializedValue = GetValue(property)
});
}
return values;
}
private void SetValue(SettingsPropertyValue propertyValue)
{
XmlNode targetNode = IsGlobal(propertyValue.Property)
? _globalSettingsNode
: _localSettingsNode;
XmlNode settingNode = targetNode.SelectSingleNode(string.Format("setting[#name='{0}']", propertyValue.Name));
if (settingNode != null)
settingNode.InnerText = propertyValue.SerializedValue.ToString();
else
{
settingNode = _rootDocument.CreateElement("setting");
XmlAttribute nameAttribute = _rootDocument.CreateAttribute("name");
nameAttribute.Value = propertyValue.Name;
settingNode.Attributes.Append(nameAttribute);
settingNode.InnerText = propertyValue.SerializedValue.ToString();
targetNode.AppendChild(settingNode);
}
}
private string GetValue(SettingsProperty property)
{
XmlNode targetNode = IsGlobal(property) ? _globalSettingsNode : _localSettingsNode;
XmlNode settingNode = targetNode.SelectSingleNode(string.Format("setting[#name='{0}']", property.Name));
if (settingNode == null)
return property.DefaultValue != null ? property.DefaultValue.ToString() : string.Empty;
return settingNode.InnerText;
}
private bool IsGlobal(SettingsProperty property)
{
foreach (DictionaryEntry attribute in property.Attributes)
{
if ((Attribute)attribute.Value is SettingsManageabilityAttribute)
return true;
}
return false;
}
private XmlNode GetSettingsNode(string name)
{
XmlNode settingsNode = _rootNode.SelectSingleNode(name);
if (settingsNode == null)
{
settingsNode = _rootDocument.CreateElement(name);
_rootNode.AppendChild(settingsNode);
}
return settingsNode;
}
public XmlDocument GetBlankXmlDocument()
{
XmlDocument blankXmlDocument = new XmlDocument();
blankXmlDocument.AppendChild(blankXmlDocument.CreateXmlDeclaration("1.0", "utf-8", string.Empty));
blankXmlDocument.AppendChild(blankXmlDocument.CreateElement(_rootNodeName));
return blankXmlDocument;
}
public void Reset(SettingsContext context)
{
_localSettingsNode.RemoveAll();
_globalSettingsNode.RemoveAll();
_xmlDocument.Save(_filePath);
}
public SettingsPropertyValue GetPreviousVersion(SettingsContext context, SettingsProperty property)
{
// do nothing
return new SettingsPropertyValue(property);
}
public void Upgrade(SettingsContext context, SettingsPropertyCollection properties)
{
}
}
}
The List in the SoundClips class is having special characters converted to a 'safe' format. I.e. < becomes < and it's including a second xml header, but I can't figure out why. Here is an example output of the settings file being generated:
<?xml version="1.0" encoding="utf-8"?>
<settings>
<globalSettings>
<setting name="SecondaryOutputDeviceID">-1</setting>
<setting name="InjectMicOutputDeviceID">1</setting>
<setting name="InjectMicInputDeviceID">0</setting>
<setting name="PrimaryOutputDeviceID">-1</setting>
<setting name="InjectMicEnabled">False</setting>
<setting name="SoundBinds"><?xml version="1.0" encoding="utf-16"?>
<SoundClips xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Items>
<SoundKeyBind>
<FilePath>D:\Sounds\Example.mp3</FilePath>
<FileName>Example.mp3</FileName>
<Volume>0.5</Volume>
<KeyBindText>Shift + A</KeyBindText>
<KeyBind>
<Modifier>4</Modifier>
<Key>A</Key>
</KeyBind>
</SoundKeyBind>
</Items>
</SoundClips></setting>
</globalSettings>
</settings>
Special characters are being escaped because you're setting InnerText instead of InnerXml.
Here is an example showing the difference between the two in MSDN.
I have a wpf app with an xml Config File.
I made a ViewModel class who is Binded to the MainWindow.xaml, and I'm making some validators using IDataErrorInfo and a ValidationRule class.
What I want is, if the user changes a value, and the value passes the validation, the config class becomes serialized to xml.
For the save I have a class extension:
public static class ConfiguracionExtension
{
public static void Save(this Configuration configXML)
{
string ConfigPath = AppDomain.CurrentDomain.BaseDirectory + "config.xml";
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
XmlSerializer serializer = new XmlSerializer(typeof(Configuration));
Stream writer = new FileStream(ConfigPath, FileMode.Create);
ns.Add("", "");
serializer.Serialize(writer, configXML, ns);
writer.Close();
}
}
The configuration class looks like:
[Serializable, XmlRoot("configuration")]
public class Configuration : IDataErrorInfo, INotifyPropertyChanged
{
private int _minute;
[XmlElement]
public int minute
{
get
{
return _minute;
}
set
{
_minute = value;
OnPropertyChanged("minute");
}
}
public static Configuration Load()
{
string ConfigPath= AppDomain.CurrentDomain.BaseDirectory + "config.xml";
if (File.Exists(ConfigPath))
{
try
{
XmlSerializer _s = new XmlSerializer(typeof(Configuration));
return (Configuration)_s.Deserialize(new XmlTextReader(ConfigPath));
}
catch (Exception ex)
{
Auxiliar.writeError(ex.ToString());
return new Configuration();
}
}
else
return new Configuration();
}
public Configuracion()
{
minutes = 60;
}
#region IDataErrorInfo Members
public string Error
{
get { return String.Empty; }
}
public string this[string columnName]
{
get
{
String errorMessage = String.Empty;
switch (columnName)
{
case "minute":
if (minute < 1)
{
errorMessage = "minutes can't be less than 1";
}
break;
}
return errorMessage;
}
}
#endregion
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(String propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
and the validation rule looks like:
public class MinutesValidation : ValidationRule
{
private int _min;
public int Minimum
{
get { return _min; }
set { _min = value; }
}
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
int minute;
Boolean noIllegalChars;
noIllegalChars = int.TryParse(value.ToString(), out minute);
if (value.ToString().Length < 1)
{
return new ValidationResult(false, "Value can't be empty");
}
else if (noIllegalChars == false)
{
return new ValidationResult(false, "Ilegal Character");
}
else
{
return new ValidationResult(true, null);
}
}
}
Ok, I Solved, but if anyone gets a better option I'll be very greatful.
What I've done is on the config file I added a loaded boolean who starts on false, and I added a condition to the save function to work only when the loaded is true.
The config class now is like this:
[Serializable, XmlRoot("configuration")]
public class Configuration : IDataErrorInfo, INotifyPropertyChanged
{
private int _minute;
[XmlElement]
public int minute
{
get
{
return _minute;
}
set
{
_minute = value;
this.Save();
OnPropertyChanged("minute");
}
}
[XmlIgnore]
public bool loaded;
public static Configuration Load()
{
string ConfigPath= AppDomain.CurrentDomain.BaseDirectory + "config.xml";
if (File.Exists(ConfigPath))
{
try
{
XmlSerializer _s = new XmlSerializer(typeof(Configuration));
var tempConf = (Configuracion)_s.Deserialize(new XmlTextReader(ConfigPath));
tempConf.loaded = false;
return tempConf;
}
[...]
}
public Configuracion()
{
loaded = false;
minutes = 60;
}
[...]
}
I added a loaded event to the main window, and when it's fired it sets the loaded property to true.
Why is it not possible to have this ?
[ConfigurationProperty(typeof(CCfgElement).ToString())]
I get the error:
Error 1 An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
here is my code
public class CConfigElement<T> : ConfigurationElement
{
}
public class CConfigSection<CCfgElement> : ConfigurationSection where CCfgElement : CConfigElement<CCfgElement>
{
// Create a element.
[ConfigurationProperty(typeof(CCfgElement).ToString())]
public CCfgElement Element
{
get { return (CCfgElement)this[typeof(CCfgElement).ToString()]; }
set { this[typeof(CCfgElement).ToString()] = value; }
}
}
I do not think there is any workarounds but
can anybody tell me how to add a section lement with code?
Søren
I found a kind of solution my self
here is my code
// create the DataModel in your MainWindow or App
// CTestDataModel t = new CTestDataModel();
public class CTestDataModel
{
CTestValues _Cfg;
// Create values to save in cofig
public class CTestValues : ConfigurationElement
{
[ConfigurationProperty("Param", DefaultValue = 11, IsRequired = true)]
public int Param
{
get { return (int)this["Param"]; }
set { this["Param"] = value; }
}
[ConfigurationProperty("Param1", DefaultValue = "22", IsRequired = true)]
public double Param1
{
get { return (double)this["Param1"]; }
set { this["Param1"] = value; }
}
[ConfigurationProperty("Time", IsRequired = true)]
public DateTime Time
{
get { return (DateTime)this["Time"]; }
set { this["Time"] = value; }
}
}
public CTestDataModel()
{
// load config
_Cfg = CConfiguration.Element<CTestValues>();
// Use values
int t = _Cfg.Param;
_Cfg.Param = 5;
_Cfg.Param1 = 6;
_Cfg.Time = new DateTime(1962, 10, 10);
}
}
public class CConfigSection<CCfgElement> : ConfigurationSection where CCfgElement : ConfigurationElement
{
// Create a element.
[ConfigurationProperty("Element")]
public CCfgElement Element
{
get { return (CCfgElement)this["Element"]; }
set { this["Element"] = value; }
}
}
public static class CConfiguration
{
static Configuration config = null;
static AppSettingsSection appSettings = null;
static CConfiguration()
{
config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
appSettings = config.AppSettings;
AppDomain.CurrentDomain.ProcessExit += CConfiguration_Dtor;
}
private static void CConfiguration_Dtor(object sender, EventArgs e)
{
config.Save(ConfigurationSaveMode.Modified, true);
}
// Uses sections
private static String MakeSectionName(String name)
{
return name.Replace('+', '.');
}
public static void RemoveSection(Type T)
{
try
{
String name = MakeSectionName(T.ToString());
config.Sections.Remove(name);
}
catch (Exception)
{
return;
}
}
public static T Element<T>() where T : ConfigurationElement
{
try
{
return Section<T>().Element;
}
catch (Exception ex)
{
Debug.WriteLine(typeof(T).ToString()+" error: "+ex.Message);
throw ex;
}
}
public static CConfigSection<T> Section<T>() where T : ConfigurationElement
{
try
{
return Section(typeof(T).ToString(), new CConfigSection<T>()) as CConfigSection<T>;
}
catch (Exception ex)
{
Debug.WriteLine(typeof(T).ToString()+" error: "+ex.Message);
throw ex;
}
}
public static ConfigurationSection Section(String name, ConfigurationSection section)
{
try
{
name = MakeSectionName(name);
ConfigurationSection cs = config.Sections.Get(name);
if (cs == null)
{
config.Sections.Add(name, section);
return section;
}
else
return cs;
}
catch (Exception)
{
config.Sections.Remove(name);
config.Sections.Add(name, section);
return section;
}
}
// Uses AppSettings
public static bool Exist(String key)
{
return appSettings.Settings[key] != null;
}
public static string Read(String key, string Default = "")
{
if (Exist(key))
return appSettings.Settings[key].Value;
return Default;
}
public static void Write(string key, string value)
{
if (Exist(key))
appSettings.Settings.Remove(key);
appSettings.Settings.Add(key, value);
}
public static void Remove(string key)
{
if (Exist(key))
appSettings.Settings.Remove(key);
}
public static new string ToString()
{
StringBuilder sb = new StringBuilder();
// Get the settings collection (key/value pairs).
if (appSettings.Settings.Count != 0)
{
foreach (string key in appSettings.Settings.AllKeys)
{
string value = appSettings.Settings[key].Value;
sb.Append(String.Format("Key: {0} Value: {1}\r\n", key, value));
}
}
return sb.ToString();
}
}
I have an extension method for System.Object to serialize and deserialize objects using Json.Net. this is my Extension methods:
public static void SaveToFile(this object data, string FileName)
{
using (StreamWriter writer = new StreamWriter(FileName))
{
string encode = WpfApplication.Helper.Encrypt(JsonConvert.SerializeObject(data));
writer.Write(encode);
writer.Close();
}
}
public static void LoadFromFile<t>(this object data, string FileName)
{
using (StreamReader reader = new StreamReader(FileName))
{
data = JsonConvert.DeserializeObject<t>(WpfApplication.Helper.Decrypt(reader.ReadToEnd()));
reader.Close();
}
}
and It's the class that I want to deserialize:
public class CardPack
{
#region Properties
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private List<FlashCard> cards;
public List<FlashCard> Cards
{
get { return cards; }
set { cards = value; }
}
private bool registered;
public bool Registered
{
get { return registered; }
set { registered = value; }
}
private int currentCardIndex;
public int CurrentCardIndex
{
get { return currentCardIndex; }
set { currentCardIndex = value; }
}
public string RegisterKey { get; set; }
public string ViewName { get; set; }
public List<FlashCard> TodayCards { get; set; }
#endregion
~CardPack()
{
foreach (FlashCard card in cards)
{
card.Check();
}
currentCardIndex = 0;
TodayCards = null;
this.SaveToFile(string.Format(System.IO.Path.GetDirectoryName(
System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase).Split(#"file:\\")[1] + #"\Packs\{0}.json", name));
}
but whenever I deserialize the class cards is empty and I don't know how to resolve the problem. Can anybody help me?
Update
I find the error when I had this code:
public CardPack(string Name)
{
this.name = Name;
this.LoadFromFile<CardPack>(string.Format(System.IO.Path.GetDirectoryName(
System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase).Split(#"file:\\")[1] + #"\Packs\{0}.json", name));
foreach (var item in cards)
{
if (item.NextTime == null)
{
int a = 0;
}
}
TodayCards = cards.Where(c => c.NextTime.Date == DateTime.Today).ToList();
}
because the application closed when it tries to run foreach (var item in cards)!
I asked here and found out that cards is empty!
update2 I serialized the CardPack object with a little different structure. in previous structure Cards property was read-only.
I found that data = JsonConvert.DeserializeObject<t>(WpfApplication.Helper.Decrypt(reader.ReadToEnd())); in extension method doesn't change to 'data' class then Cards in CardPack is always null. I'll ask a question to find out why I cant set the class from it's extension method later.
when for Perperty created a private field,Do it is compulsor??
and when do not created?
enter code here
namespace ApplicationStartSample
{
public class Configuration
{
private Configuration()
{
}
private static Configuration _Current;
public static Configuration Current
{
get
{
if (_Current == null)
_Current = new Configuration();
return _Current;
}
}
private const string Path = "Software\\MFT\\Registry Sample";
public bool EnableWelcomeMessage
{
get
{
return bool.Parse(Read("EnableWelcomeMessage", "false"));
}
set
{
Write("EnableWelcomeMessage", value.ToString());
}
}
public string Company //why do not create private field?
{
get
{
return Read("Company", "MFT");
}
set
{
Write("Company", value);
}
}
public string WelcomeMessage
{
get
{
return Read("WelcomeMessage", string.Empty);
}
set
{
Write("WelcomeMessage", value);
}
}
public string Server
{
get
{
return Read("Server", ".\\Sqldeveloper");
}
set
{
Write("Server", value);
}
}
public string Database
{
get
{
return Read("Database", "Shop2");
}
set
{
Write("Database", value);
}
}
private static string Read(string name, string #default)
{
RegistryKey key = Registry.CurrentUser.OpenSubKey(Path, false);
if (key == null)
return #default;
try
{
string result = key.GetValue(name).ToString();
key.Close();
return result;
}
catch
{
return #default;
}
}
private static void Write(string name, string value)
{
try
{
RegistryKey key = Registry.CurrentUser.OpenSubKey(Path, true);
if (key == null)
key = Registry.CurrentUser.CreateSubKey(Path);
key.SetValue(name, value);
key.Close();
}
catch
{
}
}
}
}
If you're asking if you can eliminate the private field for your Current property, you could do this (though it would no longer initialise Configuration lazily):
public class Configuration
{
static Configuration()
{
Current = new Configuration();
}
public static Configuration Current { get; private set; }
}
Note: This is an Auto-Implemented Property and requires C# 3.0.
You could also use a public field instead (though if you ever need to change this to a property, you would need to recompile anything that's calling it):
public class Configuration
{
public static Configuration Current = new Configuration();
}