Deserialize XML into C# Windows Form - c#

I've got an XML file that is created via my Windows form to save two text fields and 2 date time pickers.
I am wondering how to "load" (preferably by asking the user where the file is) this back into my form so that it can be edited and saved again.
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;}
}
Save Button on my form
void SavebuttonClick(object sender, EventArgs e)
{
DialogResult dialogResult = MessageBox.Show("Are you sure you want to save?",
"Save", MessageBoxButtons.YesNo);
if (dialogResult == DialogResult.Yes)
{
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);
}
}
Third Part
public void SaveValues(Values v)
{
XmlSerializer serializer = new XmlSerializer(typeof(Values));
using (TextWriter textWriter = new StreamWriter(#"E:\TheFile.xml"))
{
serializer.Serialize(textWriter, v);
}
}

You can do this:
public void SomeMethod()
{
Values v = LoadValues();
this.task1_name.Text = v.task1_name;
this.task1_desc.Text = v.task1_desc;
this.task1_date.Value = v.task1_date;
this.task1_time.Value = v.task1_time;
}
public Values LoadValues()
{
XmlSerializer serializer = new XmlSerializer(typeof(Values));
using (TextReader textReader = new StreamReader(#"E:\TheFile.xml"))
{
return (Values)serializer.Deserialize(textReader);
}
}
I recommend to have the serializer in one variable so it won't be created each time (it's expensive to construct a new XmlSerializer)
Hope it helps

You can deserialize the xml into an object and use that object to reload the fields..
For that first create the xsd for that xml using xsd.exe.. Then you can create the class file using the same exe and deserialize the xml into that object using XmlSerializer.

You can parse the xml and update the form with the parsed data. There is a file picker dialog in visual studio for the user to select a file.
XmlTextReader reader = new XmlTextReader ("books.xml");
while (reader.Read())
{
// code
}

Related

C# Saving into an XML document

I try to save an object to an XML Document.
I always get an inner Exception Error.
I think it has to do something with boxing and unboxing but i cannot help myself.
So here we go:
The Method for XML Saving
public class Saveclass
//
public static void Save(string filename, List<Class> classlist)
{
StreamWriter writer = new StreamWriter(filename, false, Encoding.UTF8);
XmlSerializer serializer = new XmlSerializer(typeof(class));
serializer.Serialize(writer,classlist);//Here i get the error at classlist
writer.Close();
}
And here the SaveFile Dialog
private void SaveButton(object sender, EventArgs e)
{
SaveFileDialog dialog = new SaveFileDialog();
dialog.Filter = "XML Data|*.xml";
if (dialog.ShowDialog() == DialogResult.OK)
{
List<class> classlist = null;
foreach (ListViewItem item in this.listViewWinforms.Items)
{
classlist = new List<class>();
}
Saveclass.Save(dialog.FileName, classlist)
}
}
In the Basic i have a Listview with Items inside and want to save these Items in my listview to an XML Document
Error is
System.InvalidOperationException: 'Trying to generate an XML Document
InvalidCastException: The object of the Type "System.Collections.Generic.List`1[Namespace.Class]" cannot cast into"Namespace.Class"
There is a type mismatch.
You are defining your serializer as:
new XmlSerializer(typeof(class));
Which is configured to serialize objects of type class.
However, you are then trying to serialize the classlist object, which is not a class but a List<Class>.
Try defining your serializer as:
new XmlSerializer(typeof(List<Class>));
By the way, naming your class class is very confusing. You should try to name your classes more descriptively.
I think you need to change just one line:
Just use typeof(List) instead of typeof(class))
XmlSerializer serializer = new XmlSerializer(typeof(List<Class>));
Here is a small example
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
using System.IO;
namespace ConsoleApplication1
{
public class Program
{
public static void Main(string[] args)
{
List<Car> myList = new List<Car>();
myList.Add(new Car(){ Name = "Beetle", Brand = "VW", Price = 5999.9M });
myList.Add(new Car(){ Name = "Corolla", Brand = "Toyota", Price = 49999.9M });
Saveclass.Save("carlist.xml",myList);
}
}
public static class Saveclass
{
public static void Save(string filename, List<Car> classlist)
{
StreamWriter writer = new StreamWriter(filename, false, Encoding.UTF8);
XmlSerializer serializer = new XmlSerializer(typeof(List<Car>));
serializer.Serialize(writer,classlist);
writer.Close();
}
}
public class Car
{
public string Name {get;set;}
public string Brand {get; set;}
public decimal Price {get; set;}
}
}
You can test here

Serializing and deserializing a collection of objects

I'm trying to create an Rssfeed reader which saves info about a podcast to a JSON file and I'm having trouble serializing and deserializing to that file.
I realize that there are other threads regarding this subject, but I cannot grasp or comprehend how to apply it to my code or the reasoning behind it.
So I have a bit of code that creates a file if it doesn't exist and writes JSON data to it which looks like:
public void SaveFile(Podcast podcast)
{
try
{
JsonSerializer serializer = new JsonSerializer();
if(!File.Exists(#"C: \Users\Kasper\Desktop\Projektuppgift\Projektuppgift - Delkurs2\Projektet\Projektet\bin\Debug\podcasts.json"))
{
string json = JsonConvert.SerializeObject( new { Podcast = podcast });
StreamWriter sw = File.CreateText(#"C:\Users\Kasper\Desktop\Projektuppgift\Projektuppgift-Delkurs2\Projektet\Projektet\bin\Debug\podcasts.json");
using (JsonWriter writer = new JsonTextWriter(sw))
{
serializer.Serialize(writer, json);
}
}
else
{
var filepath = #"C:\Users\Kasper\Desktop\Projektuppgift\Projektuppgift-Delkurs2\Projektet\Projektet\bin\Debug\podcasts.json";
var jsonData = File.ReadAllText(filepath);
var podcasts = JsonConvert.DeserializeObject<List<Podcast>>(jsonData) ?? new List<Podcast>();
podcasts.Add(podcast);
jsonData = JsonConvert.SerializeObject(new {PodcastList = podcasts });
File.WriteAllText(filepath, jsonData);
}
}
catch (Exception ex)
{
Console.WriteLine("IO Exception ", ex.Message);
}
}
What I can't get to work is to deserialize from this file and add an object to it. Is there an easier way to add more data to the JSON file or am I missing something?
The Podcast class looks like this:
public class Podcast
{
public string url { get; set; }
public string name { get; set; }
public int updateInterval { get; set; }
public string category { get; set; }
//public Category category = new Category();
public List<Episode> episodes { get; set; }
public Podcast(string url, string name, Category category, List<Episode> episodes, int updateInterval)
{
this.url = url;
this.name = name;
this.category = category.name;
this.episodes = episodes;
this.updateInterval = updateInterval;
}
public Podcast(Podcast p)
{
this.url = p.url;
this.name = p.name;
this.category = p.category;
this.episodes = p.episodes;
this.updateInterval = p.updateInterval;
}
}
There appear to be a couple of issues here:
You are checking for the existence of a different file than the one you are reading/writing. The former filename has extra spaces in it. The best way to avoid this problem is to use a variable to contain the filename rather than hardcoding it in three separate places.
You are inconsistent about the JSON format you are writing and reading:
When you first create the file (in the first branch), you are writing a JSON object that contains a property Podcast which then contains a single podcast.
When you attempt to read the JSON file, you are treating the entire JSON as a list of podcasts.
After tacking the new podcast onto the list, you are writing the JSON as a single object containing a PodcastList property, which then contains the list.
You need to use a consistent JSON format. I would recommend breaking your code into smaller methods to read and write the podcasts.json file like this so that it is easier to reason about:
public static List<Podcast> ReadPodcastsFromFile(string filepath)
{
if (!File.Exists(filepath)) return new List<Podcast>();
string json = File.ReadAllText(filepath);
return JsonConvert.DeserializeObject<List<Podcast>>(json);
}
public static void WritePodcastsToFile(List<Podcast> podcasts, string filepath)
{
string json = JsonConvert.SerializeObject(podcasts);
// This will overwrite the file if it exists, or create a new one if it doesn't
File.WriteAllText(filepath, json);
}
Then, you can simplify your SaveFile method down to this (I would be tempted to rename it to SavePodcast):
public void SaveFile(Podcast podcast)
{
var filepath = #"C:\Users\Kasper\Desktop\Projektuppgift\Projektuppgift-Delkurs2\Projektet\Projektet\bin\Debug\podcasts.json";
List<Podcast> podcasts = ReadPodcastsFromFile(filepath);
podcasts.Add(podcast);
WritePodcastsToFile(podcasts, filepath);
}
Notice I've also removed the exception handling from SaveFile. You should move that up to wherever SaveFile is called, so that you can take appropriate action at that point if an exception is thrown, e.g.:
try
{
SaveFile(podcast);
}
catch (Exception ex)
{
// Show a message to the user indicating that the file did not save
}
I'm just still learning c# but it might be that you deserialise into a list of podcasts and when you serialise you're serliasing into an object type.

Append to the last node of xml file c#

Each time i get a request from a user, i have to serialize and append it , to an existing xml file like this :
<LogRecords>
<LogRecord>
<Message>Some messagge</Message>
<SendTime>2017-12-13T22:04:40.1109661+01:00</SendTime>
<Sender>Sender</Sender>
<Recipient>Name</Recipient>
</LogRecord>
<LogRecord>
<Message>Some message too</Message>
<SendTime>2017-12-13T22:05:08.5720173+01:00</SendTime>
<Sender>sender</Sender>
<Recipient>name</Recipient>
</LogRecord>
</LogRecords>
Currently Serializing data in this way (which works fine):
var stringwriter = new StringWriter();
var serializer = new XmlSerializer(object.GetType());
serializer.Serialize(stringwriter, object);
var smsxmlStr = stringwriter.ToString();
var smsRecordDoc = new XmlDocument();
smsRecordDoc.LoadXml(smsxmlStr);
var smsElement = smsRecordDoc.DocumentElement;
var smsLogFile = new XmlDocument();
smsLogFile.Load("LogRecords.xml");
var serialize = smsLogFile.CreateElement("LogRecord");
serialize.InnerXml = smsElement.InnerXml;
smsLogFile.DocumentElement.AppendChild(serialize);
smsLogFile.Save("LogRecords.xml");
And the properties class
[XmlRoot("LogRecords")]
public class LogRecord
{
public string Message { get; set; }
public DateTime SendTime { get; set; }
public string Sender { get; set; }
public string Recipient { get; set; }
}
But what i want to do is to load the file, navigate to the last element/node of it and append a new List<LogRecord> and save, so i can easily deserialize later.
I have tried various ways using XPath Select Methods like SelectSingleNode and SelectNodes but since i am junior with c# i haven't manage to make them work properly. Does anyone have any idea on how to serialize and append properly?
Thank you
Your approach (and most of the answers given to date) rely on having all of the log file in memory in order to append more records to it. As the log file grows, this could cause issues (such as OutOfMemoryException errors) down the road. Your best bet is to use an approach that streams the data from the original file into a new file. While there might be a few bugs in my untested code. The approach would look something like the following:
// What you are serializing
var obj = default(object);
using (var reader = XmlReader.Create("LogRecords.xml"))
using (var writer = XmlWriter.Create("LogRecords2.xml"))
{
// Start the log file
writer.WriteStartElement("LogRecords");
while (reader.Read())
{
// When you see a record in the original file, copy it to the output
if (reader.NodeType == XmlNodeType.Element && reader.LocalName == "LogRecord")
{
writer.WriteNode(reader.ReadSubtree(), false);
}
}
// Add your additional record(s) to the output
var serializer = new XmlSerializer(obj.GetType());
serializer.Serialize(writer, obj);
// Close the tag
writer.WriteEndElement();
}
// Replace the original file with the new file.
System.IO.File.Delete("LogRecords.xml");
System.IO.File.Move("LogRecords2.xml", "LogRecords.xml");
Another idea to consider, does the log file need to be a valid XML file (with the <LogRecords> tag at the start and finish? If you omit the root tag, you could simply append the new records at the bottom of the file (which should be very efficient). You can still read the XML in .Net by creating an XmlReader with the right ConformanceLevel. For example
var settings = new XmlReaderSettings()
{
ConformanceLevel = ConformanceLevel.Fragment
};
using (var reader = XmlReader.Create("LogRecords.xml", settings))
{
// Do something with the records here
}
Try using xml linq :
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
LogRecord record = doc.Descendants("LogRecord").Select(x => new LogRecord()
{
Message = (string)x.Element("Message"),
SendTime = (DateTime)x.Element("SendTime"),
Sender = (string)x.Element("Sender"),
Recipient = (string)x.Element("Recipient")
}).OrderByDescending(x => x.SendTime).FirstOrDefault();
}
}
public class LogRecord
{
public string Message { get; set; }
public DateTime SendTime { get; set; }
public string Sender { get; set; }
public string Recipient { get; set; }
}
}
You can perform it by using XDocument like this;
XDocument doc = XDocument.Load("LogRecords.xml");
//Append Node
XElement logRecord = new XElement("LogRecord");
XElement message = new XElement("Message");
message.Value = "Message";
XElement sendTime = new XElement("SendTime");
sendTime.Value = "SendTime";
XElement sender = new XElement("Sender");
sender.Value = "Sender";
XElement recipient = new XElement("Recipient");
recipient.Value = "Recipient";
logRecord.Add(message);
logRecord.Add(sendTime);
logRecord.Add(sender);
logRecord.Add(recipient);
doc.Element("LogRecords").Add(logRecord);
//Append Node
doc.Save("LogRecords.xml");

How can I serialize a class to XML using Windows Phone 8 SDK?

I've got one attribute (_XMLPlaylist) that I want to serialize in a XML-file likeshown in the code:
private void btn_Save_Click(object sender, RoutedEventArgs e)
{
_Playlist.Pl_Name = tb_Name.Text.ToString();
_XMLPlaylist.Playlists.Add(_Playlist);
IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication();
using (IsolatedStorageFileStream isoStream = new IsolatedStorageFileStream(StudiCast.Resources.AppResources.Playlists, FileMode.CreateNew, isoStore))
{
using (StreamWriter writer = new StreamWriter(isoStream))
{
var ser = new XmlSerializer(typeof(XMLPlaylist));
ser.Serialize(writer, _XMLPlaylist);
writer.Close();
}
isoStream.Close();
}
}
The Type XMLPlaylist looks as follows:
class XMLPlaylist
{
public XMLPlaylist()
{
Playlists = new List<Playlist>();
}
public List<Playlist> Playlists;
}
And the class Playlist like that:
class Playlist
{
public Playlist()
{
Casts = new List<Cast>();
}
public string Pl_Name;
public List<Cast> Casts;
}
'Cast' owns two strings. In .NET 4 I used the keyword [Serializable] in front of the class's name but there isn't the [Serializable]-attribute anymore.
Need fast Help please!
Edit:
Error at 'var ser = new XmlSerializer(typeof(XMLPlaylist));':
In System.InvalidOperationException an unhandled error of type "System.Xml.Serialization.ni.dll" occurs.
XmlSerializer can serialize only public classes - make your class XMLPlaylist public (also all properties/classes you want to serialize - so Playlist should be public as well).

Serializing a textbox in C# .net

I am a beginner with .NET environment.
I have a windows application with three textboxes and one button. When the user clicks on the button, i want all the textbox values to be serialized in an XML format to a file.
I tried doing it this way,
DialogResult dr = new DialogResult();
private void button1_Click(object sender, EventArgs e)
{
AddCustomer customer = new AddCustomer();
customer.textBox1.Text = textBox1.Text;
customer.textBox2.Text = textBox2.Text;
customer.textBox3.Text = textBox3.Text;
customer.textBox4.Text = textBox4.Text;
saveFileDialog1.InitialDirectory = #"D:";
saveFileDialog1.Filter = "Xml Files | *.xml";
if (saveFileDialog1.ShowDialog().Equals(DialogResult.OK))
{
SerializeToXML(customer);
}
}
public void SerializeToXML(AddCustomer customer)
{
XmlSerializer serializer = new XmlSerializer(typeof(AddCustomer));
TextWriter textWriter = new StreamWriter(#"D:\customer.xml");
serializer.Serialize(textWriter, customer);
textWriter.Close();
}
this returned system.invalidoperationexception was unhandled exception
any ideas?
Thanks,
Michael
You can't serialize controls instead you have to create Serializable component that represent TextBox values. (For more detail read MSDN article).
For instance,
[Serializable]
public class Customer
{
public string Name { get; set; }
public string Address {get;set;}
}
You shouldn't serialize the textbox object, only their values.
customer.textBox1 should be customer.text1 of type string. You then need to just assign customer.text1 = textbox1.text.
Also, mark your AddCustomer class with the [Serializable] attribute.
Edit: This is a code I just tried and it works fine. See if you can make it work in your solution.
Add new class Customer
[Serializable]
public class Customer
{
public string FullName { get; set; }
public string Age { get; set; }
}
Try to serialize it like this
Customer customer = new Customer();
customer.FullName = "John"; // or customer.FullName = textBox1.Text
customer.Age = "21"; // or customer.Age = textBox2.Text
XmlSerializer serializer = new XmlSerializer(typeof(Customer));
TextWriter textWriter = new StreamWriter(#"D:\customer.xml");
serializer.Serialize(textWriter, customer);
textWriter.Close();
After doing this, I got an xml file created with the following content.
<?xml version="1.0" encoding="utf-8"?>
<Customer xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<FullName>John</FullName>
<Age>21</Age>
</Customer>
Try and compare to see what you are doing wrong.
There are a lot of ways to write XML in .NET. Here is a way using XmlWriter that works for very simple content like in this case:
string text1 = /* get value of textbox */;
string text2 = /* get value of textbox */;
string text3 = /* get value of textbox */;
// Set indent=true so resulting file is more 'human-readable'
XmlWriterSettings settings = new XmlWriterSettings() { Indent = true };
// Put writer in using scope; after end of scope, file is automatically saved.
using (XmlWriter writer = XmlTextWriter.Create("file.xml", settings))
{
writer.WriteStartDocument();
writer.WriteStartElement("root");
writer.WriteElementString("text1", text1);
writer.WriteElementString("text2", text2);
writer.WriteElementString("text3", text3);
writer.WriteEndElement();
}
One note: you should avoid doing file operations on the UI thread as this can result in blocking behavior (e.g. the disk can be slow and cause the UI to freeze up while it writes the file, or it could be writing to a network location and hang for a while as it connects). It is best to put up a progress dialog and display a message "Please wait while file is saved..." and do the file operation in the background; a simple way is to post the background operation the thread pool using BeginInvoke/EndInvoke.
If you want to use the XmlSerializer instead, then you would follow these steps:
Create a public type to act as the root element of your document and mark it with XmlRoot.
Add elements/attributes made of either primitive/built-in types or your own public custom types which are also XML serializable, marking them with XmlElement or XmlAttribute as necessary.
To write the data out, use XmlSerializer.Serialize with an appropriate Stream, StreamWriter, or XmlWriter along with your root object.
To read the data back in, use XmlSerializer.Deseralize with an appropriate Stream, TextReader, or XmlReader, casting the return type back to your root object.
Full sample.
The type to serialize:
[XmlRoot("customer")]
public class CustomerData
{
// Must have a parameterless public constructor
public CustomerData()
{
}
[XmlElement("name")]
public string Name { get; set; }
[XmlElement("city")]
public string City { get; set; }
[XmlElement("company")]
public string Company { get; set; }
public override string ToString()
{
return
"Name=[" + this.Name + "] " +
"City=[" + this.City + "] " +
"Company=[" + this.Company + "]";
}
}
The code to read/write the data:
// Initialize the serializer to write and read the data
XmlSerializer serializer = new XmlSerializer(typeof(CustomerData));
// Initialize the data to serialize
CustomerData dataToWrite = new CustomerData()
{
Name = "Joel Spolsky",
City = "New York",
Company = "Fog Creek Software"
};
// Write it out
XmlWriterSettings settings = new XmlWriterSettings() { Indent = true };
using (XmlWriter writer = XmlTextWriter.Create("customer.xml", settings))
{
serializer.Serialize(writer, dataToWrite);
}
// Read it back in
CustomerData dataFromFile = null;
using (XmlReader reader = XmlTextReader.Create("customer.xml"))
{
dataFromFile = (CustomerData)serializer.Deserialize(reader);
}
Console.WriteLine(dataFromFile);

Categories

Resources