Hey guys I am working on a program that will take a person's name and comment and then serialize it to a binary file. It must also be able to deserialize and load the data to the form. I need it to be able to go up and down the list of files(names and comments) by using buttons on the form.
In my code I have it separated into a class that builds the object and the code for the form, and no i'm not allowed to separate it. (Just in case anyone thought that'd work)
the form code:
private void btnAdd_Click(object sender, EventArgs e)
{
bool blnValid = true;
if (string.IsNullOrWhiteSpace(txtName.Text))
{
MessageBox.Show("Please enter a valid name");
}
if (string.IsNullOrWhiteSpace(txtComment.Text))
{
MessageBox.Show("Please enter a valid comment");
blnValid = false;
}
if (blnValid)
{
//create class instance and assign property values
//set file name
DateTime CurrentDate = DateTime.Now;
string strFileName;
strFileName = CurrentDate.ToString("dd-MM-yy-hh-mm-ss") + ".bin";
// serialize object to binary file
MessageBox.Show(strFileName);
Enquiry newEnquiry = new Enquiry();
newEnquiry.Name = txtName.Text;
newEnquiry.Comment = txtComment.Text;
newEnquiry.DOB = dteDOB.Value;
newEnquiry.WriteToFile(strFileName, newEnquiry);
}
}
private void btnLoad_Click(object sender, EventArgs e)
{
}
private void btnPrevious_Click(object sender, EventArgs e)
{
}
and the class code:
[Serializable]
class Enquiry
{
//stores the various values into the enquiry class.
public string Name { get; set; }
public DateTime DOB { get; set; }
public string Comment { get; set; }
//creates the file, if there isn't one, writes the file, and
//disables sharing while the program is active. It also formats
//the file into binary
public void WriteToFile(string strFileName, Enquiry newEnquiry)
{
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream(strFileName, FileMode.Create, FileAccess.Write, FileShare.None);
formatter.Serialize(stream, newEnquiry);
stream.Close();
}
// this loads the files and translates them to plain text
public void ReadFromFile(string strFileName, Enquiry newEnquiry)
{
Stream stream = File.OpenRead(strFileName);
BinaryFormatter formatter = new BinaryFormatter();
newEnquiry = (Enquiry)formatter.Deserialize(stream);
stream.Close();
}
I don't know what you are asking, but if you need methods to serialize and deserialize, use these:
public static void BinarySerializeObject(string path, object obj)
{
using (StreamWriter streamWriter = new StreamWriter(path))
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
try
{
binaryFormatter.Serialize(streamWriter.BaseStream, obj);
}
catch (SerializationException ex)
{
throw new SerializationException(((object) ex).ToString() + "\n" + ex.Source);
}
}
}
public static object BinaryDeserializeObject(string path)
{
using (StreamReader streamReader = new StreamReader(path))
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
object obj;
try
{
obj = binaryFormatter.Deserialize(streamReader.BaseStream);
}
catch (SerializationException ex)
{
throw new SerializationException(((object) ex).ToString() + "\n" + ex.Source);
}
return obj;
}
}
Related
I am getting the error "Exception thrown: 'System.NotSupportedException' in mscorlib.ni.dll Memory stream is not expandable" when trying to serialize and save an instance of a custom class object.
Here are my saving/loading methods:
public void SerializeObject<T>(T serializableObject, string fileName)
{
if (serializableObject == null) { return; }
try
{
XmlDocument xmlDocument = new XmlDocument();
XmlSerializer serializer = new XmlSerializer(serializableObject.GetType());
using (MemoryStream stream = new MemoryStream())
{
// convert string to stream
byte[] byteArray = Encoding.UTF8.GetBytes(fileName);
MemoryStream fileNameStream = new MemoryStream(byteArray);
serializer.Serialize(stream, serializableObject);
stream.Position = 0;
xmlDocument.Load(stream);
xmlDocument.Save(fileNameStream);
stream.Dispose();
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
Debug.WriteLine(TAG + serializableObject.ToString() + " saved");
}
public T DeSerializeObject<T>(string fileName)
{
if (string.IsNullOrEmpty(fileName)) { return default(T); }
T objectOut = default(T);
try
{
string attributeXml = string.Empty;
// convert string to stream
byte[] byteArray = Encoding.UTF8.GetBytes(fileName);
MemoryStream stream = new MemoryStream(byteArray);
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(stream);
string xmlString = xmlDocument.OuterXml;
using (StringReader read = new StringReader(xmlString))
{
Type outType = typeof(T);
XmlSerializer serializer = new XmlSerializer(outType);
using (XmlReader reader = XmlReader.Create(read))
{
objectOut = (T)serializer.Deserialize(reader);
reader.Dispose();
}
read.Dispose();
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
if (objectOut != null) Debug.WriteLine(TAG + objectOut.ToString() + " loaded");
return objectOut;
}
And here is the object class that I'm trying to save:
public class EntryDataType
{
readonly string TAG = "EntryDataType: ";
private static int idCounter = -1;
public int id;
private EntryDataType parentEdt;
public EntryDataType parentEdtProperty
{
get { return parentEdt; }
set { parentEdt = value; }
}
// row control is not serializable, so ignore it when saving
[XmlIgnore]
public RowControl linkedRowControl;
public int indent = -1;
public int index = -1;
public int linearIndex = -1;
private bool completed = false;
public bool completedProperty {
get { return completed; }
set
{
// set hidden state and set all children's hidden state, i.e. they will do the same
completed = value;
foreach (var item in childList)
{
item.linkedRowControl.SetCompleted(value);
}
}
}
public ChildList<EntryDataType> childList;
public bool bulletButtonChecked;
public string textboxText;
public EntryDataType()
{
// assign unique id to each entry
id = idCounter;
idCounter++;
//Debug.WriteLine(TAG + "new entry " + id + " created");
childList = new ChildList<EntryDataType>();
childList.parentEdtOfChildListProperty = this;
}
}
I've already rewritten the class to eliminate it's constructor's parameters, and to ignore the unserializeable RowControl member. I am just learning .NET and c# so don't fully know what I'm doing yet; any help is greatly appreciated. Thanks :)
OK, I think I see what you are trying to do - serialize and deserialize an object to/from a file. Your way is a bit complicated, it could be simplified, for example like this:
public static void SerializeObject<T>(T serializableObject, string fileName)
{
if (serializableObject == null) { return; }
try
{
XmlSerializer serializer = new XmlSerializer(serializableObject.GetType());
using (Stream stream = File.Open(fileName, FileMode.Create))
{
serializer.Serialize(stream, serializableObject);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
public static T DeSerializeObject<T>(string fileName)
{
if (string.IsNullOrEmpty(fileName)) { return default(T); }
try
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (Stream stream = File.Open(fileName, FileMode.Open))
{
return (T)serializer.Deserialize(stream);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
return default(T);
}
There is no need to read/write to a MemoryStream first. You can serialize and deserialize straight from the file.
Also, when using using, there is no need to dispose the object (like your stream.Dispose(); line) - that's what the dispose is for (with the added bonus that if there's an exception, the object will be disposed as well).
I haven't tried this with your class but it should work fine. Give it a try and see if it works.
byte[] byteArray = Encoding.UTF8.GetBytes(fileName);
MemoryStream fileNameStream = new MemoryStream();
...
xmlDocument.Save(fileNameStream);
I made a class called MyData and marked it with [Serializable], but it doesn't seem to work...
Here's MyData.cs:
namespace Forms_Bot_Rebuild
{
[Serializable]
public class MyData
{
private String _Email;
private String _Password;
private String _WorldId;
public MyData(string email, string password, string worldid)
{
_Email = email;
_Password = password;
_WorldId = worldid;
}
public string Email
{ get { return _Email; } set { _Email = value; } }
public string Password
{ get { return _Password; } set { _Password = value; } }
public string WorldId
{ get { return _WorldId; } set { _WorldId = value; } }
}
}
Here's Form1.cs:
private void button1_Click(object sender, EventArgs e)
{
MyData data = new MyData(boxEmail.Text, boxPass.Text, boxWorldId.Text);
string objectNode = Serialize.ToJsonString(data);
File.WriteAllText(Application.StartupPath + #"\LoginData.json", objectNode);
}
private void button2_Click(object sender, EventArgs e)
{
object myData;
myData = Serialize.Deserialize<MyData>(new FileStream(Application.StartupPath + #"\LoginData.json", FileMode.Open));
boxEmail.Text = data.Email;
boxPass.Text = data.Password;
boxWorldId.Text = data.WorldId;
}
Here's Serialize.cs:
public class Serialize
{
public static StreamReader ToStreamReader(object o)
{
MemoryStream stream = new MemoryStream();
DataContractJsonSerializer ser = new DataContractJsonSerializer(o.GetType());
ser.WriteObject(stream, o);
stream.Position = 0;
StreamReader sr = new StreamReader(stream);
return sr;
}
public static string ToJsonString(object o)
{
MemoryStream stream = new MemoryStream();
DataContractJsonSerializer ser = new DataContractJsonSerializer(o.GetType());
ser.WriteObject(stream, o);
stream.Position = 0;
StreamReader sr = new StreamReader(stream);
return sr.ReadToEnd();
}
public static object Deserialize<T>(Stream stream)
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
stream.Position = 0;
T t = (T)ser.ReadObject(stream);
return t;
}
}
Also, this code was given to me by a friend, so I asked him. He couldn't understand it too. I asked another friend, who, in my opinion, knew decent C#, but he couldn't fix it too.
An unhandled exception of type 'System.Runtime.Serialization.SerializationException' occurred in System.Runtime.Serialization.dll
Additional information: Expecting element 'root' from namespace ''.. Encountered 'None' with name '', namespace ''.
Any opinions?
You should use
[DataContract]
instead of
[Serializable]
and mark all the properties with
[DataMember]
(but funnily, on my PC works even with Serializable, only it serializes fields instead of properties... Mmmh I see someone else noticed it: http://pietschsoft.com/post/2008/02/27/NET-35-JSON-Serialization-using-the-DataContractJsonSerializer)
Note that Deserialize could have this signature:
public T Deserialize<T>(Stream stream)
and you should close streams after using them:
MyData myData;
using (var fs = new FileStream(Application.StartupPath + #"\LoginData.json""LoginData.json", FileMode.Open))
{
myData = (MyData)Serialize.Deserialize<MyData>(fs);
}
If instead you really want to know what you wrote in the title:
Each serialization class/method look for "its" serialization attributes (at this time there are at least three families of attributes in Microsoft .NET: [Serializable], the [Xml*] family, the [DataContract]. Plus if you use JSON.NET there are its [Json*] attributes. Stop. So depending on the class/method you want to use to serialize your data, you have to know which attributes it will look for.
I currently have this code.
This is the code I actually use to read the file:
public ObservableCollection<Esame> rigaEsame = new ObservableCollection<Esame>();
private void ReadFile()
{
Esami.ItemsSource = rigaEsame;
IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile("exams.txt", FileMode.OpenOrCreate, FileAccess.Read);
string tmp;
string tmp2;
using (StreamReader reader = new StreamReader(fileStream))
{
while (!reader.EndOfStream)
{
tmp = reader.ReadLine();
tmp2 = reader.ReadLine();
rigaEsame.Insert(0, new Esame(tmp,tmp2));
Debug.WriteLine(tmp);
}
}
}
This code is the one I use to write to the file:
private void InsertEntry_click(object sender, RoutedEventArgs e)
{
IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
using (StreamWriter writeFile = new StreamWriter(new IsolatedStorageFileStream("exams.txt", FileMode.Append, FileAccess.Write, myIsolatedStorage)))
{
writeFile.WriteLine(Subject.Text);
writeFile.WriteLine(Date.Text);
writeFile.Close();
}
NavigationService.Navigate(new Uri("/Views/MainPage.xaml",UriKind.Relative));
}
and this is the class file:
public class Esame
{
public string nomeEsame { get; set; }
public string descrizioneEsame { get; set; }
public string Name
{
get { return nomeEsame; }
set { nomeEsame = value; }
}
public Esame(string esame, string descrizione)
{
nomeEsame = esame;
descrizioneEsame = descrizione;
}
}
I am currently able to write the text from the TextBlock "Subject" and place it into my "Esami" LongListSelector. Still, I am currently unable to correctly read/write the second text string, coming from the TextBlock named "Date".
How may I do that? I suppose there is something wrong with the class itself or the way I use it when putting it into my LongListSelector list item.
How may i fix that?
I've been following a guide on Binary Serialization (this one here: http://www.codeproject.com/Articles/1789/Object-Serialization-using-C) and I think I finally almost have it working. When I save the file is created, but when I try to load, nothing is loaded. I feel like I'm close to getting this working. Any advice would be appreciated. Here's the code:
Save/Load class
[Serializable()]
public class SaveLoad : ISerializable
{
public int GameDay = Date.GameDay;
public List<Adventurer> Adventurers = FormMain.AdventurerManager.AdventurerList;
public SaveLoad()
{
GameDay = 0;
Adventurers = null;
}
public SaveLoad(SerializationInfo info, StreamingContext ctxt)
{
GameDay = (int)info.GetValue("Date", typeof(int));
Adventurers = (List<Adventurer>)info.GetValue("Adventurers", typeof(List<Adventurer>));
}
public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
{
info.AddValue("Date", GameDay);
info.AddValue("Adventurers", Adventurers);
}
}
Save/Load methods:
void btnSaveGame_Click(object sender, EventArgs e)
{
SaveLoad save = new SaveLoad();
Stream stream = File.Open("SaveGame.osl", FileMode.Create);
BinaryFormatter bformatter = new BinaryFormatter();
bformatter.Serialize(stream, save);
stream.Close();
}
void btnLoadGame_Click(object sender, EventArgs e)
{
SaveLoad load = new SaveLoad();
Stream stream = File.Open("SaveGame.osl", FileMode.Open);
BinaryFormatter bformatter = new BinaryFormatter();
load = (SaveLoad)bformatter.Deserialize(stream);
stream.Close();
Date.CalculateDate();
this.Visible = false;
((FormMain)(this.ParentForm)).ControlMainScreen.Visible = true;
}
I think you may just have an initialization timing issue.
Try either moving you initialization of the GameDay and Adventurers to the constructor or get rid of the nulling them out in the constructor. Once I did the following, the code pretty much works:
public SaveLoad()
{
//GameDay = null;
//Adventurers = null;
}
Note I had to also make sure that the Adventurer class had the Serialization attribute.
Here is the code with the serialization that works for me (I had to create my own Adventurer class and I replaced the date with a string since I couldn't figure out what you were doing with it or where it was coming from. I also populated the adventurers list with some dummy data and commented out anything to do with the form stuff that I also didn't have information on.
[Serializable()]
public class SaveLoad : ISerializable
{
public string GameDay = null;
public List<Adventurer> Adventurers = null;
//FormMain.AdventurerManager.AdventurerList;
public SaveLoad()
{
GameDay = "Date";
Adventurers = new List<Adventurer>() { new Adventurer { Name = "a1", Type = "t1" }, new Adventurer { Name = "a1", Type = "t1" } }; ;
}
public SaveLoad(SerializationInfo info, StreamingContext ctxt)
{
GameDay = (string)info.GetValue("Date", typeof(string));
Adventurers = (List<Adventurer>)info.GetValue("Adventurers", typeof(List<Adventurer>));
}
public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
{
info.AddValue("Date", GameDay);
info.AddValue("Adventurers", Adventurers);
}
}
[Serializable()]
public class Adventurer
{
public string Name { get; set; }
public string Type { get; set; }
}
private void btnLoadGame_Click(object sender, EventArgs e)
{
SaveLoad sl = new SaveLoad();
Stream stream = File.Open("SaveGame.osl", FileMode.Open);
BinaryFormatter bformatter = new BinaryFormatter();
sl = (SaveLoad)bformatter.Deserialize(stream);
stream.Close();
MessageBox.Show(sl.Adventurers.Count.ToString());
//Date.CalculateDate();
//this.Visible = false;
//((Form1)(this.ParentForm)).ControlMainScreen.Visible = true;
}
private void btnSaveGame_Click(object sender, EventArgs e)
{
SaveLoad sl = new SaveLoad();
Stream stream = File.Open("SaveGame.osl", FileMode.Create);
BinaryFormatter bformatter = new BinaryFormatter();
bformatter.Serialize(stream, sl);
stream.Close();
}
EDIT
#JasonHaley is right, you have a timing/initialization issue.
During your Load button click event your defining a new SaveLoad called "Load"
This creates a reference to the FormMain.AdventurerManager.AdventurerList
But during deserialization this reference is destroyed by the object that was serialized to disk (the other list of adventurers) and is now a DIFFERENT list of adventurers from the one defined in your FormMain.AdventurerManager.AdventurerList
You need to load into that list specifically...
void btnLoadGame_Click(object sender, EventArgs e)
{
Stream stream = File.Open("SaveGame.osl", FileMode.Open);
BinaryFormatter bformatter = new BinaryFormatter();
SaveLoad load = (SaveLoad)bformatter.Deserialize(stream);
// ***********************************
FormMain.AdventurerManager.AdventurerList = SaveLoad.Adventurers
// ***********************************
stream.Close();
Date.CalculateDate();
this.Visible = false;
((FormMain)(this.ParentForm)).ControlMainScreen.Visible = true;
}
im stuck with this stupid form... heres my code. It saves it where the streamwriter wants it to but when i save it where the user wants via the savedialog box is creates the XML but doesnt put anything in it! Can someone have a look as it's starting to wind me up!
void SavebuttonClick(object sender, EventArgs e)
{
Stream myStream ;
SaveFileDialog savefile1 = new SaveFileDialog();
savefile1.Filter = "xml files |*.xml" ;
savefile1.FilterIndex = 2 ;
savefile1.RestoreDirectory = true ;
if(savefile1.ShowDialog() == DialogResult.OK)
{
if((myStream = savefile1.OpenFile()) != null)
{
Values v = new Values();
v.task1_name = this.task1_name.Text;
v.task1_desc = this.task1_desc.Text;
v.task1_date = this.task1_date.Value;
v.task1_time = this.task1_time.Value;
SaveValues(v);
}
myStream.Close();
}
}
This is the streamwriter...
public void SaveValues(Values v)
{
XmlSerializer serializer = new XmlSerializer(typeof(Values));
using(TextWriter textWriter = new StreamWriter(#"E:\TheFileYouWantToStore.xml"))
{
serializer.Serialize(textWriter, v);
}
...
}
EDIT:
public class Values
{
public string task1_name { get; set;}
public string task1_desc { get; set;}
public DateTime task1_date { get; set;}
public DateTime task1_time { get; set;}
}
I presume this is the code you meant, im fairly new to coding though mate :(
You must call textWriter.close(); after serialize. If you don't close writer it won't apply chenges to file.
By the way you are writing values to E:\TheFileYouWantToStore.xml. your save save method does not use users file.
public void SaveValues(Values v)
{
XmlSerializer serializer = new XmlSerializer(typeof(Values));
using(TextWriter textWriter = new StreamWriter(#"E:\TheFileYouWantToStore.xml"))
{
serializer.Serialize(textWriter, v);
textWriter.close();
}
...
}
EDIT:
if(savefile1.ShowDialog() == DialogResult.OK)
{
Values v = new Values();
v.task1_name = this.task1_name.Text;
v.task1_desc = this.task1_desc.Text;
v.task1_date = this.task1_date.Value;
v.task1_time = this.task1_time.Value;
SaveValues(savefile1.FileName, v);
}
-
public void SaveValues(string fileName, Values v)
{
XmlSerializer serializer = new XmlSerializer(typeof(Values));
using(TextWriter textWriter = new StreamWriter(fileName))
{
serializer.Serialize(textWriter, v);
textWriter.close();
}
...
}