Serialize multiple objects into XML - c#

I try the following code to serialize my objects into xml file, but when run this code the last item in the list values serialize by the count for the list.
I want to serialize every item in the list? what is the wrong in my code
Can anyone help me ?
//list of class values
List<values> valus = new List<values>();
values value = new values();
foreach (Control control in Controls)
{
value.ctrlname = control.Name.ToString();
value.ctrllocation = control.Location.ToString();
value.ctrltext = control.Text.ToString();
value.ctrltype = control.GetType().ToString();
value.ctrlstatus = control.Enabled.ToString();
valus.Add(value);
}
System.Xml.Serialization.XmlSerializer writer =
new System.Xml.Serialization.XmlSerializer(typeof(values));
var path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "//Serialization.xml";
System.IO.FileStream file = System.IO.File.Create(path);
foreach (values item in valus)
{
writer.Serialize(file, item);
}
file.Close();

First lets validate that your classes are serialzble, like so:
[Serializable()]
public class rootValues
{
public rootValues()
{
valuesArray = new List<values>();
}
[XmlElement("item", typeof(values))]
public List<values> valuesList { get; set; }
}
[Serializable()]
public class values
{
[System.Xml.Serialization.XmlAttribute("ctrlname")]
public string ctrlname { get; set; }
//....
}
Second, your using the same name for the list and object
//list of class values
rootValues valusList = new rootValues();
foreach (Control control in Controls)
{
values value = new values(); // Create new element, in your code it was the same
value.ctrlname = control.Name.ToString();
value.ctrllocation = control.Location.ToString();
value.ctrltext = control.Text.ToString();
value.ctrltype = control.GetType().ToString();
value.ctrlstatus = control.Enabled.ToString();
valuesList.valuesList.Add(value);
}
System.Xml.Serialization.XmlSerializer writer = new System.Xml.Serialization.XmlSerializer(typeof(rootValues));
var path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "//Serialization.xml";
System.IO.FileStream file = System.IO.File.Create(path);
writer.Serialize(file, valusList);
file.Close();
FYI, if you want to add a list of class values you can do it like so:
//...
List<values> SomeListOfvalues = new List<values>();
// Init list
SomeListOfvalues.add(new values()); // Adding first element
SomeListOfvalues.add(new values()); // Adding second element
// Adding the whole list to our class
valuesList.valuesList.addRange(SomeListOfvalues );

write.Serialize is probably overwriting whats in the file each time rather then appending. You could try serializing the values to a string like in this question: Serialize an object to string. And then manually appending to the file with the string values.
Alternatively you could serialize the whole list rather then each value at a time.

Your first foreach loop that fills the list is repeatedly overwriting the same value object and adding new references to same object repeatedly to the List. You're not actually adding a new item to your list when you call valus.Add(value);.
Try moving the line values value = new values(); to the top of the foreach loop or, if you're particularly worried about efficiency of declaring an object multiple times, keep the line values value; outside the loop and add the line value = new values(); inside the foreach loop.

Related

How to add new item into a list without overwriting the old item

I'm exporting some data from database to excel using CLOSEDXML. I need to add the corresponding objects/item to each object in the 'newModelist' IQueryable and add all the object to new List. In my case new row were added in the list using list.add method, however the old record is replaced by the next row/object. I'm not quite what would be the correct way to implement this.
var getData = _db.Database.Where(y => y.identifier == Identifier);
var newModelist = new MainModel();
var listXML= new List<listXML>();
foreach(var item in getData)
{
newModelist.col1 = item.A;
newModelist.col2 = item.B;
newModelist.col2 = item.C;
listXML.Add(newModelist);
}
You need to understand what an instance is.
You are currently modifying the same object instance. And you are adding the same instance to the List on every iteration.
Since List only stores the reference to an instance, your List currently contains multiple references to the same instance. Each index will return the same element.
If you want individual object instances you must create each using the new keyword:
foreach(var item in getData)
{
var newModelist = new MainModel
{
col1 = item.A,
col2 = item.B,
col3 = item.C
};
listXML.Add(newModelist);
}
MainModel is a reference type and modifying the value will reflect in the all the references, so you need to create a new instance while setting the properties in the loop. Moving creation of newModelList to for loop would do
foreach(var item in getData)
{
var newModelist = new MainModel();
newModelist.col1 = item.A;
newModelist.col2 = item.B;
newModelist.col2 = item.C;
listXML.Add(newModelist);
}

How to add multiple objects list inside a list

When I add an object in bCPList after looping, all records become same as the last object inserted. Why's that happening and how could I solve this?
public List<Entity.BCPToolkitWorkplace> Load_work_Place(List<BCPToolkitWorkplace> bCPToolkit)
{
Entity.BCPToolkitWorkplace bCP = new Entity.BCPToolkitWorkplace();
List< Entity.BCPToolkitWorkplace> bCPList = new List<Entity.BCPToolkitWorkplace>();
foreach (var item in bCPToolkit)
{
bCP.txn_type = item.txn_type;
bCP.workplace_id = item.workplace_id;
bCP.workplace_name = item.workplace_name;
bCP.workplace_number = item.workplace_number;
bCPList.Add(bCP);
}
return bCPList;
}
Declare the BCP object inside the loop as follows
public List< Entity.BCPToolkitWorkplace> Load_work_Place(List< BCPToolkitWorkplace> bCPToolkit)
{
List< Entity.BCPToolkitWorkplace> bCPList = new List< Entity.BCPToolkitWorkplace>();
foreach (var item in bCPToolkit)
{
// Declaring the bcp object inside the loop
Entity.BCPToolkitWorkplace bCP = new Entity.BCPToolkitWorkplace();
bCP.txn_type = item.txn_type;
bCP.workplace_id = item.workplace_id;
bCP.workplace_name = item.workplace_name;
bCP.workplace_number = item.workplace_number;
bCPList.Add(bCP);
}
return bCPList;
}
You need to move this line to the inside of the foreach.
Entity.BCPToolkitWorkplace bCP = new Entity.BCPToolkitWorkplace();
The reason this is happening is that Entity.BCPToolkitWorkplace, apparently is defined as a class (reference-type), and you defined only one instance of that class at the top, so you were technically adding the same exact instance to the list over and over.
Take a look at the answers here for more about how reference types work.

MVC List Error List<Model>

I'm using foreach to transfer data from list to another but when adding value updated automatically to last value added. For example:
list1 = [1,2,3]
list2 = new List<Model>()
foreach(var item in list1) {
list2.Add(item)
}
the result in list2 is [ 3, 3, 3]
Actually example is below :
var _sizes = new List<ProductsSize>();
var _size = new ProductsSize();
if (model.Dynamic_ProductsSize.Count > 0)
{
foreach (var item in model.Dynamic_ProductsSize)
{
_size.SizeId = item;
_sizes.Add(_size);
}
}
model.ProductsSize = _sizes.ToList();
I need to know why it only takes the last item and what is the solution for this case
You only have one ProductsSize object:
var _size = new ProductsSize();
And you keep modifying that same object. All references to that object, including any list elements it's been added to, get updated when you modify that one object.
Instead, create your new object in the loop:
foreach (var item in model.Dynamic_ProductsSize)
{
var _size = new ProductsSize();
_size.SizeId = item;
_sizes.Add(_size);
}
That way each element in the list is a new object instead of the same object added multiple times.
Side note, you have a few things in the code which aren't necessary. Checking the length before the loop, for example, as well as converting a list to a list at the end.
In fact, I imagine all of the code shown can be shortened to simply this:
model.ProductsSize = model.Dynamic_ProductsSize.Select(p => new ProductsSize { SizeId = p }).ToList();
In which case you're also just converting one model property to another model property. Why not put this logic in the model itself and skip the whole thing?
public IEnumerable<ProductsSize> ProductsSize
{
get { return this.Dynamic_ProductsSize.Select(p => new ProductsSize { SizeId = p });
}
Unless there's a particular reason you want the same data twice in two different properties that isn't clear from this code, having one set of data and just different views/calculations/etc. of that data is often preferred.
Create a new object before adding it to the list. You can use the object initializer syntax to keep it concise:
if (model.Dynamic_ProductsSize.Count > 0)
{
foreach (var item in model.Dynamic_ProductsSize)
{
_sizes.Add(new ProductsSize(){SizeId = item});
}
}

C# (Xamarin) List, where and its changes

I don't know where an error is. I have a list of element called TileModel with default values and ObservableCollection<TileModel> list
When I show a form in my view model I have to find in this list an element with the same name. If an element in the list exists, I copy this element in the ObservableCollection.
public ObservableCollection<TileModel> testList { get; set; }
List<TileModel> dsType = new List<TileModel>() {
new TileModel() { Text = "Alarms", IconImage = "Alarm.png",
NavigateType = typeof(Alarms) },
}
In a function I have this code:
foreach (string s in items)
{
TileModel dm = dsType.Where(d => d.Text.RemoveTextBetween("(", ")").Trim() == s)
.FirstOrDefault();
if (dm != null)
{
dm.Text = UpdateTextItem(dm.Text, iType);
testList.Add(dm);
}
}
UpdateTextItem changes the name Text to add the number of records. If I follow the code with F11, when I enter in the function dsType is the original. After dm.Text = UpdateTextItem(dm.Text, iType); dsType is changed this dm.text.
In my point of view dm is a new variable with in it a value of the list but isn't an instance of an element of the list. Then why do the code change my original dsType?
Thank you in advance.
That is because your class TileModel is a reference type. That means dm is just a reference to the original object.
By:
testList.Add(dm);
you add the reference to your testList - the object is the same if it gets changed, it also changes your object in your original list.
To Avoid this. You can add the Item like this: (If your ctor allows this)
var dm_new = new TileModel(dm);
dm_new .Text = UpdateTextItem(dm_new .Text, iType);
testList.Add(dm_new );

Getting all children of specific page type

I have the following tree in EPI CMS:
[Root]
.
.
--[Lobby] ID=1
--Foo1
--Foo2
--Foo3
--[ContainerOfSubFoo] ID=2
--SubFoo1
--SubFoo2
--SubFoo3
I want when I edit Foo1, to have check boxes of all the SubFoo's.
What I have now is this:
private static List<SelectItem> GetSubFoos()
{
PageReference pRef = new PageReference(2); //(ID=2 is my container page - ContainerOfSubFoo)
PageData root = DataFactory.Instance.GetPage(pRef);
var pages = DataFactory.Instance.GetChildren<Models.Pages.SubFoo>(root.ContentLink);
List<SelectItem> targetsList = new List<SelectItem>();
foreach (var target in pages)
{
targetsList.Add(new SelectItem() { Value = target.ContentLink.ID.ToString(), Text = target.SubFooProperty });
}
return targetsList;
}
This works fine but I don't want to use ID=2, I want the GetSubFoos to go "up" (to Lobby) then go "down" to the first ContainerOfSubFoo and get all the children of SubFooType
The GetSubFoo method is on the Foo class
I can provide the code of the SelectionFactory if needed.
Another problem I see now is that the checkbox "V" does not save :/
(the string is saved with the values comma seperated but the checkboxes
are all unchecked
this was solved by adding .ToString() for the ID
From within the selection factory, you can obtain the current content via a handy extension method EPiServer.Cms.Shell.Extensions.FindOwnerContent() on the ExtendedMetadata that is passed in by EPiServer:
public virtual IEnumerable<ISelectItem> GetSelections(ExtendedMetadata metadata)
{
var selections = new List<SelectItem>();
var contentRepository = ServiceLocator.Current.GetInstance<IContentRepository>();
var ownerContent = metadata.FindOwnerContent();
if (ownerContent is Foo)
{
var containerRoot = contentRepository.GetChildren<ContainerOfSubFoo>(ownerContent.ParentLink).FirstOrDefault();
var pageOptions = contentRepository.GetChildren<SubFoo>(containerRoot.ContentLink);
foreach (var target in pageOptions)
{
selections.Add(new SelectItem() { Value = target.ContentLink.ID.ToString(), Text = target.SubFooProperty });
}
}
return selections;
}
You can then traverse the page tree to find what you need.

Categories

Resources