I have an app that creates ContactList Objects and adds them to a Dictionary collection. My ContactList objects have a property called AggLabels which is a collection of AggregatedLabel objects containg Name and Count properties. What I am trying to do is change the "else" case of my code snippet so that before adding a new AggregatedLabel it will check whether the AggLabel.Name exists in the AggregatedLabel collection and if this is true it will not add the AggLabel.Name again. Instead it will add the value of AggLabel.Count (type int) to the existing AggregatedLabel object. So for an existing object, if the first Count value was 3 and the second value is 2 then the new Count value should be 5. In simple terms I want to have unique AggLabel Names and add together the Counts where the Names are the same. Hope that makes sense - would appreciate any help. Thanks!
Code snippet
Dictionary<int, ContactList> myContactDictionary = new Dictionary<int, ContactList>();
using (DB2DataReader dr = command.ExecuteReader())
{
while (dr.Read())
{
int id = Convert.ToInt32(dr["CONTACT_LIST_ID"]);
if (!myContactDictionary.ContainsKey(id))
{
ContactList contactList = new ContactList();
contactList.ContactListID = id;
contactList.ContactListName = dr["CONTACT_LIST_NAME"].ToString();
//contactList.AggLabels = new ObservableCollection<AggregatedLabel>() { new AggregatedLabel() { Name = dr["LABEL_NAME"].ToString(), Count = Convert.ToInt32(dr["LABEL_COUNT"])}};
contactList.AggLabels = new ObservableCollection<AggregatedLabel>()
{
new AggregatedLabel()
{
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
};
myContactDictionary.Add(id, contactList);
}
else
{
ContactList contactList = myContactDictionary[id];
contactList.AggLabels.Add(
new AggregatedLabel()
{
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
);
}
}
}
There are two possible solutions I can think of:
1) Use a dictionary instead of the collection of aggregated labels the same way you do it for the contact dictionary. When yout use the name as key and the count as value, you can use the ContainsKey-Method to check whether the label already exists.
contactList.AggLabels = new Dictionary<string, int>();
...
else
{
ContactList contactList = myContactDictionary[id];
if (contactList.AggLabels.ContainsKey(dr["LABEL_NAME"].ToString()))
{
contactList.AggLabels[dr["LABEL_NAME"].ToString()] += Convert.ToInt32(dr["LABEL_COUNT"]);
}
else
{
contactList.AggLabels.Add(dr["LABEL_NAME"].ToString(), Convert.ToInt32(dr["LABEL_COUNT"]));
}
}
2) I you need to use the AggreagteLabel object you can use a loop to search throug all labels.
else
{
bool flagAggLabelFound = false;
ContactList contactList = myContactDictionary[id];
foreach(AggregateLabel aggLabel in contactList.AggLabels)
{
if(aggLabel.Name == dr["LABEL_NAME"].ToString())
{
aggLabel.Count += Convert.ToInt32(dr["LABEL_COUNT"]);
flagAggLabelFound = true;
break;
}
}
if (!flagAggLabelFound)
{
contactList.AggLabels.Add(
new AggregatedLabel()
{
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
);
}
}
I hope this helps.
I would try this:
ContactList contactList = myContactDictionary[id];
AggregateLabel existing = contactList.AggLabels.FirstOrDefault(
l => l.Name == dr["LABEL_NAME"].ToString()
);
if (existing == null) { contactList.AggLabels.Add(
new AggregatedLabel() {
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
);
}
else { existing.Count += Convert.ToInt32(dr["LABEL_COUNT"]); }
#extract these Aggregated Labels and put them in a separate Observable collection:
1) If you a Dictionary for storing the labels in the contact list, this should work:
ObservableCollection<AggregateLabel> copyOfAggregateLabels = new ObservableCollection<AggregateLabel>();
foreach (KeyValuePair<string, int> aggLabel in aggregateLabels)
{
copyOfAggregateLabels.Add(
new AggregatedLabel() {
Name = aggLabel.Key,
Count = aggLabel.Value
}
);
}
2) If you use an ObservableCollection of AggregateLabels, you get an AggregateLable instead of a KeyValuePair in the loop. The rest works the same way.
First I thought of something like:
ObservableCollection<AggregateLabel> copyOfAggregateLabels = new ObservableCollection<AggregateLabel>(aggregateLables);
But this way you get a new ObservableCollection, but the labels stored in the new collection are still referring to the same objects as the ones in the collection you copy.
Related
I have the code below. To explain there will always be values for the 'tl' variable.
At the moment its hard coded to always assume 4 columns in the row, but I want to make it work based on the count of the columns and make it build the levels based on how many columns there are, but there also needs to be a value in the column.
So at the moment if there is a value in column 2, it will build the 'ltwo' variable, and then if there is a value in column 3 it does the 'lthree'.
I want to make it build as many levels as it needs to so im not repeating code and having the same code over and over.
public static List<AdditionalPropertyType> SQLAddPropsStructured(DataTable dataTable, List<AdditionalPropertyType> currentadditionalproperties)
{
foreach (DataRow row in dataTable.Rows)
{
var tl = new AdditionalPropertyType
{
Name = row[0].ToString(),
Value = row[1].ToString()
};
if (!String.IsNullOrEmpty(row[2].ToString()))
{
var ltwo = new AdditionalPropertyType
{
Name = row[2].ToString()
};
var ltwolist = new List<AdditionalPropertyType>();
ltwolist.Add(tl);
ltwo.AdditionalProperties = ltwolist;
if (!String.IsNullOrEmpty(row[3].ToString()))
{
var lthree = new AdditionalPropertyType
{
Name = row[3].ToString()
};
var lthreelist = new List<AdditionalPropertyType>();
lthreelist.Add(ltwo);
lthree.AdditionalProperties = lthreelist;
currentadditionalproperties.Insert(0, lthree);
}
else
currentadditionalproperties.Insert(0, ltwo);
}
else
currentadditionalproperties.Insert(0, tl);
}
return currentadditionalproperties;
}
You can get the columns using the Columns property of the DataTable:
foreach (DataRow row in dataTable.Rows)
{
foreach(DataColumn column in dataTable.Columns)
{
Trace.WriteLine(column.ColumnName + " = " + row[column]);
}
}
You probably want to do something like this: (written on the websites, some minor typos can be present)
You need to iterate the additional columns and check if there is a value present. When there is a value, create a backup reference and renew your property.
public static List<AdditionalPropertyType> SQLAddPropsStructured(DataTable dataTable, List<AdditionalPropertyType> currentadditionalproperties)
{
// check if there are atleast 2 columns defined
if(dataTable.Columns.Count < 2)
throw new Exception("At least two columns are required");
// The result
var currentadditionalproperties = new List<AdditionalPropertyType>();
// iterate the rows
foreach (DataRow row in dataTable.Rows)
{
// create the base property
var tl = new AdditionalPropertyType
{
Name = row[0].ToString(),
Value = row[1].ToString()
};
// check the rest of the columns for additional names
foreach(int index=2;index<dataTable.Columns.Count;index++)
{
var columnValue = row[index].ToString();
// if the column is empty, discontinue the iteration
if(String.IsNullOrEmpty(columnValue))
break;
// create a backup reference.
var previous = tl;
// create a new AdditionalPropertyType
var tl = new AdditionalPropertyType { Name = columnValue };
// Create the list
tl.AdditionalProperties = new List<AdditionalPropertyType>();
// add the previous (backup reference)
tl.AdditionalProperties.Add(previous);
}
// insert the 'chain' of additional properties on the list at possition 0
currentadditionalproperties.Insert(0, tl);
}
// return the list
return currentadditionalproperties;
}
The first step is to reverse your condition and make use of the keyword continue
public static List<AdditionalPropertyType> SQLAddPropsStructured(DataTable dataTable, List<AdditionalPropertyType> currentadditionalproperties)
{
foreach (DataRow row in dataTable.Rows)
{
var tl = new AdditionalPropertyType
{
Name = row[0].ToString(),
Value = row[1].ToString()
};
if (String.IsNullOrEmpty(row[2].ToString())){
currentadditionalproperties.Insert(0, tl);
continue;
}
var ltwo = new AdditionalPropertyType
{
Name = row[2].ToString()
};
var ltwolist = new List<AdditionalPropertyType>();
ltwolist.Add(tl);
ltwo.AdditionalProperties = ltwolist;
if (String.IsNullOrEmpty(row[3].ToString())) {
currentadditionalproperties.Insert(0, ltwo);
continue;
}
var lthree = new AdditionalPropertyType
{
Name = row[3].ToString()
};
var lthreelist = new List<AdditionalPropertyType>();
lthreelist.Add(ltwo);
lthree.AdditionalProperties = lthreelist;
currentadditionalproperties.Insert(0, lthree);
}
return currentadditionalproperties;
}
Now, the code is clearer. The next step is to collect the repeating cases. Note the second case onward is repeating. Thus, do further simplification:
public static List<AdditionalPropertyType> SQLAddPropsStructured(DataTable dataTable, List<AdditionalPropertyType> currentadditionalproperties)
{
foreach (DataRow row in dataTable.Rows)
{
var tlprev = new AdditionalPropertyType
{
Name = row[0].ToString(),
Value = row[1].ToString()
};
bool isTlUpdated = true;
for (int i = 2; i <= 3; ++i) { //change this according to your need
if (String.IsNullOrEmpty(row[i].ToString()) && isTlUpdated){
currentadditionalproperties.Insert(0, tlprev);
isTlUpdated = false;
break; //note that this will now change to break to break from the current for-loop
}
var lnext = new AdditionalPropertyType
{
Name = row[i].ToString()
};
var lnextlist = new List<AdditionalPropertyType>();
lnextlist.Add(tlprev);
lnext.AdditionalProperties = lnextlist;
tlprev = lnext; //need to record this for the next loop or end of the case
isTlUpdated = true;
}
if (isTlUpdated) //correction by Jeroen
currentadditionalproperties.Insert(0, tlprev);
}
return currentadditionalproperties;
}
The key is to simplify the code step-by-step
You haven't posted all your code, so I had to guess in a couple of places (such as what the "currentAdditionalProperties" does).
I think that the below code illustrates what you want to do by making the logic extendable depending on how many columns the data table has.
The trick is to just store the "last thing" in a variable, so it can be used for the "current thing". At the end, whatever was the "last thing" is what you want to store in your "currentAdditionalProperties" object. I have commented so you can see the logic.
private List<AdditionalPropertyType> SQLAddPropsStructured(DataTable dataTable)
{
AdditionalPropertyType lastNewType; // to remember the previous new instance
// for all rows...
foreach (DataRow row in dataTable.Rows)
{
// the first type takes name and value from the first two fields
AdditionalPropertyType newType = new AdditionalPropertyType();
newType.Name = row[0].ToString();
newType.Value = row[1].ToString();
// remember this type: it is used as the AdditionalProperties for the NEXT type
lastNewType = newType;
// additional types start from field 2
int field = 2;
// iterate until we find a NULL field.
// If you want to check for the end of the fields rather than a NULL value, then instead use:
// while(field < dataTable.Columns.Count)
while(!String.IsNullOrEmpty(row[field].ToString()))
{
// create new type
var newSubType = new AdditionalPropertyType();
// get name
Name = row[field].ToString();
// new type takes the PREVIOUS type as its additional parameters
List<AdditionalPropertyType> propertyData = new List<AdditionalPropertyType>();
propertyData.Add(lastNewType);
newSubType.AdditionalProperties = propertyData;
// remember THIS type for the NEXT type
lastNewType = newSubType;
// process next field (if valid)
field++;
}
// put the last set of properties found into the current properties
currentAdditionalProperties.Insert(0, lastNewType);
return currentAdditionalProperties;
}
}
I'm working with a tree structure of Installation Places: each one may contain child InstallationPlaces and these can also contain children and so on and so on. I've got the following function:
public JsonResult GetInstPlacesTree()
{
InstallationPlaceModel ipm = new InstallationPlaceModel();
var dataContext = ipm.getRootInstallationPlaces();
var instPlaces = from ip in dataContext.installationPlaces
select new
{
id = ip.installationPlace.id,
Name = ip.installationPlace.mediumDescription,
};
return Json(instPlaces, JsonRequestBehavior.AllowGet);
}
This function returns only the root level of the tree.
I have got two working methods:
one returns the root Installation Places;
the other returns the children of a given Installation Place;
They both return IEnumerable variables.
getRootInstallationPlaces();
getChildInstallationPlaces(id);
How can I achieve to call all the Installation Places and respective children?
I have tried this alternative to the GetInstPlacesTree() function:
private IEnumerable<TreeViewItemModel> GetDefaultInlineData()
{
InstallationPlaceModel ipm = new InstallationPlaceModel();
List<TreeViewItemModel> fullTree = new List<TreeViewItemModel>();
var gipo = ipm.getChildInstallationPlaces(currentInstallationPlace.InstallationPlaceId);
List<TreeViewItemModel> childTree = new List<TreeViewItemModel>();
if (gipo.installationPlaces.Count() > 0)
{
foreach (wsInstallationPlace.installationPlaceOutput child in gipo.installationPlaces)
{
TreeViewItemModel childTreeItem = new TreeViewItemModel
{
Text = child.installationPlace.mediumDescription,
Id = child.installationPlace.id
};
childTree.Add(childTreeItem);
}
}
TreeViewItemModel fatherTreeItem = new TreeViewItemModel
{
Text = currentInstallationPlace.InstallationPlaceMediumDescription,
Id = currentInstallationPlace.InstallationPlaceId,
Items = childTree
};
fullTree.Add(fatherTreeItem);
return fullTree;
}
Any help?
I think something like the following should do what you are after. Essentially it keeps your initial method almost as-is but it populates the child Items of each top-level with a recursive call.
The recursive call grabs the children and adds each child to a List<TreeViewItemModel> to be returned but their children are in turn populated by a call to the recursive function. The recursion will end when there are no children left:
public JsonResult GetInstPlacesTree()
{
InstallationPlaceModel ipm = new InstallationPlaceModel();
var dataContext = ipm.getRootInstallationPlaces();
var instPlaces = from ip in dataContext.installationPlaces
select new TreeViewItemModel
{
id = ip.installationPlace.id,
Name = ip.installationPlace.mediumDescription,
Items = getChildInstallationPlacesRecursive(ip.installationPlace.id, ipm)
};
return Json(instPlaces, JsonRequestBehavior.AllowGet);
}
public List<TreeViewItemModel> getChildInstallationPlacesRecursive(int id, InstallationPlaceModel ipm)
{
List<TreeViewItemModel> children = new List<TreeViewItemModel>();
var gipo = ipm.getChildInstallationPlaces(id);
foreach (wsInstallationPlace.installationPlaceOutput child in gipo.installationPlaces)
{
children.Add(new TreeViewItemModel
{
Text = child.installationPlace.mediumDescription,
Id = child.installationPlace.id,
Items = getChildInstallationPlacesRecursive(child.installationPlace.id, ipm)
});
}
return children;
}
To make it recursive, you have to think that child places are, at the same time, roots of their own childs, then you can call the same function for them.
private IEnumerable<TreeViewItemModel> RecursivePlaces(InstallationPlace root){
var output = new List<TreeViewItemModel>();
output.add(new TreeViewItemModel
{
Text = root.installationPlace.mediumDescription,
Id = root.installationPlace.id
});
foreach(var child in root.installationPlaces)
output.AddRange(RecursivePlaces(child));
return output;
}
//Initial call
RecursivePlaces(ipm.getRootInstallationPlace());
You can solve this without recursion with following approach. I wrote it in some kind of pseudo-code, so you will get an idea what I suggest to accomplish, I didn't used your exact function names and structures and classes...
queue = new List<>();
queue.Add(initialInstallation);
retVal = new List<>();
while (queue.Count > 0) {
retVal.Add(queue[0].GetData());
queue.Add(queue[0].GetChildren());
queue.Remove(0);
}
return retVal;
I am using SuiteTalk web services (v. 2013_2) . I am trying to create an ItemFulfillment where the items in it were related to items that had a lot or serial number.
When I try to save this item fulfillment into NetSuite I get an error of :
Please commit inventorydetail on this line.
I was attempting to set the itemFulfillment.serialNumbers and itemFulfillment.binNumbers when I create the itemFulfillmentItem.
For example I set
nsIfItem.serialNumbers = "SNum(5)"
nsIfItem.binNumbers = "BNum(5)"
based on those properties being- A comma delimited list of serial or LOT numbers. If entering serial numbers there must be a number for each item.
Lot numbers must be entered in a format of LOT#(Quantity).
For example, to enter a quantity of 100 items as Lot number ABC1234, enter ABC1234(100).
Do I also need to set something else on the itemFulfillment or how do I get rid of that error.
I'm not sure if this question is still active, but I had the same issue and iI couldn't find much help on it. I solved this issue by creating the inventory assignment objects and adding to the transaction.
First, create the initialize ref for Item Fulfillment and assign the returned record to a variable:
InitializeRecord ir = new InitializeRecord();
ir.type = InitializeType.itemFulfillment;
InitializeRef iref = new InitializeRef();
iref.typeSpecified = true;
iref.type = InitializeRefType.salesOrder;
iref.internalId = 'Sales Order internalID';
ir.reference = iref;
ReadResponse getInitResp = _service.initialize(ir);
ItemFulfillment ifrec = (ItemFulfillment)getInitResp.record;
Get the list of items on the initialized transaction:
ItemFulfillmentItemList ifitemlist = ifrec.itemList;
Create a list to which to add each unique item being fulfilled:
List<ItemFulfillmentItem> ifitems = new List<ItemFulfillmentItem>();
Run the following code for each item in initialized transaction's item list:
If the current line item has already been added to the ifitems list, add the current Fulfillment line as an assignment to that item:
InventoryAssignment assignment = new InventoryAssignment
{
issueInventoryNumber = new RecordRef { internalId = 'internalID',
type = 'RecordType',
typeSpecified = true
}
};
List<InventoryAssignment> list = new List<InventoryAssignment>();
list.Add(assignment);
ifitemlist.item[b].inventoryDetail = new InventoryDetail
{
inventoryAssignmentList = new InventoryAssignmentList
{
inventoryAssignment = list.ToArray()
}
};
ifitemlist.item[b].quantity += 'quantity shipped';
If the line item has not yet been added, create new line item:
ItemFulfillmentItem ffItem = new ItemFulfillmentItem();
ffItem.item = ifitemlist.item[b].item;
ffItem.itemReceive = true;
ffItem.itemReceiveSpecified = true;
ffItem.itemIsFulfilled = true;
itemIsFulfilled = true;
ffItem.itemIsFulfilledSpecified = true;
ffItem.orderLineSpecified = true;
ffItem.orderLine = ifitemlist.item[b].orderLine;
//Check if serialized
if (Your fulfillment item contains serialized data)
{
ffItem.serialNumbers = 'Serial numbers';
InventoryAssignment assignment = new InventoryAssignment
{
issueInventoryNumber = new RecordRef {
internalId = 'Inventory internal ID',
type = RecordType,
typeSpecified = true
}
};
ffItem.inventoryDetail = new InventoryDetail
{
inventoryAssignmentList = new InventoryAssignmentList
{
inventoryAssignment = new InventoryAssignment[]
{
assignment
},
replaceAll = false
},
nullFieldList = new string[] { },
customForm = new RecordRef { }
};
}
ffItem.quantity = 'QUANTITY SHIPPED';
ffItem.quantitySpecified = true;
ifitems.Add(ffItem);
Finally, add your "ifitems" list to your Item Fulfillment and add this to NetSuite:
ItemFulfillmentItemList ifitemlistToFulfill = new ItemFulfillmentItemList();
ifitemlistToFulfill.replaceAll = false;
ifitemlistToFulfill.item = ifitems.ToArray();
ItemFulfillment newItemFulfill = new ItemFulfillment();
newItemFulfill.itemList = ifitemlistToFulfill;
_service.add(newItemFulfill);
I have a problem with my foreach loop. The prupose is to loop through items in a listbox and for every item there is, it should set the properties of the person equal to the properties of the person equal to a person object which i will insert into a list of persons.(The person has a item, with properties ect..). Problem: It inserts the first person with it's item into the list, but when it comes to the second person that it has to insert it changes the first person data to the same data as the second person data, and inserts the second person. So it always inserts the new person but changes all my old data that I have alredy inserted too be the same as the new person's.
private void btnOK_Click(object sender, EventArgs e)
{
bool bOK = false;
if (UC.IsEmpty(txtFirstName) || UC.IsEmpty(txtLastName) || UC.IsEmpty(txtID) || lstItemsAdded.Text == null) //Maak seker van die listItemsAdded se content... hier sal n error wees... j kan nog n else maak dat hy spesefiek toets of daar items in die lstbox is
{
UC.MB("Customer Information Missing", "Please supply enough customer information");
}
else
{
bOK = true;
}
if (bOK)
{
foreach (Item item in lstItemsAdded.Items)
{
PersonItemObject.FirstName = txtFirstName.Text;
PersonItemObject.LastName = txtLastName.Text;
PersonItemObject.ID = txtID.Text;
PersonItemObject.Email = txtEmail.Text;
PersonItemObject.Age = Convert.ToInt32(txtAge.Text);
PersonItemObject.Item.ItemCode = item.ItemCode;
PersonItemObject.Item.ItemDescription = item.ItemDescription;
PersonItemObject.Item.ItemName = item.ItemName;
PersonItemObject.Item.ItemPrice = item.ItemPrice;
It is supposed to add all the items in the listBox to the list in the next statement, and for each item it should add the persons details too.
PersonItemsList.Add(PersonItemObject);
If I added more than 1 item to a person it changes my old data that i have added in the list to be the same as then new person data, and inserts a new person into the list too.
}
DialogResult = DialogResult.OK;
Close();
}
}
In every iteration you are updating properties of the same object, and then inserting it into the list. SO in the end list contains several referencies to the same object.
What you should do is craeting new object for each iteration:
foreach (Item item in lstItemsAdded.Items)
{
PersonItem item = new PersonItem(); //just guessing the type here
item.FirstName = txtFirstName.Text;
...
PersonItemsList.Add(item);
}
You should create a new instance of your "PersonItemObject". Something like:
PersonItemObject = new PersonItemObjectClass()
as the first sentence of your loop, being PersonItemObjectClass the type of PersonItemObject. The problem here is, probably, you are using always the same instance and because of it the value is always changing.
You've got to create a new instance of whatever type PersonItemObject is, inside the foreach loop.
What you're adding to the PersonItemsList is actually a reference to a single instance of your class. Every time you iterate the loop, you're updating the same instance, so you have a list of identical looking objects.
foreach (Item item in lstItemsAdded.Items)
{
var PersonItemObject = new PersonItem();
PersonItemObject.FirstName = txtFirstName.Text;
PersonItemObject.LastName = txtLastName.Text;
...
PersonItemsList.Add(PersonItemObject);
}
You may want to read up on the differences between value types and reference types.
You have one PersonItemObject and you are changing it in every iteration.If you want to make a list of PersonItemObjects then create a new instance on each iteration:
foreach (Item item in lstItemsAdded.Items)
{
var PersonItemObject = new YourType();
PersonItemObject.FirstName = txtFirstName.Text;
PersonItemObject.LastName = txtLastName.Text;
...
}
This is happening because you're always changing the same PersonItemObject. You should create a new version of this object each time and add it your list.
foreach (Item item in lstItemsAdded.Items)
{
var newObject = new PersonItemObject();
newObject.FirstName = txtFirstName.Text;
newObject.LastName = txtLastName.Text;
newObject.ID = txtID.Text;
newObject.Email = txtEmail.Text;
newObject.Age = Convert.ToInt32(txtAge.Text);
newObject.Item.ItemCode = item.ItemCode;
newObject.Item.ItemDescription = item.ItemDescription;
newObject.Item.ItemName = item.ItemName;
newObject.Item.ItemPrice = item.ItemPrice;
PersonItemsList.Add(newObject);
}
You are not creating a new object each time you are setting the values to it. To create a new object the proper way would be like this:
foreach (Item item in lstItemsAdded.Items)
{
var newObject = new PersonItemObject()
{
FirstName = txtFirstName.Text;
LastName = txtLastName.Text;
ID = txtID.Text;
Email = txtEmail.Text;
Age = Convert.ToInt32(txtAge.Text);
Item.ItemCode = item.ItemCode;
Item.ItemDescription = item.ItemDescription;
Item.ItemName = item.ItemName;
Item.ItemPrice = item.ItemPrice;
}
PersonItemsList.Add(newObject);
}
I'm trying to write to a model for the first time to use in my view: the first time I write to the model I get an ArgumentOutOfRangeException.
Getting error on first write to array:
private IAdditionalQuestionsService _service;
private SelectedAdditionalQuestionAnswerModel _model;
private void InitializeController()
{
_service = GetObject<IAdditionalQuestionsService>();
//GetPageHeaderText(inst);
ViewBag.GetPageTitle = "Additional Questions";
}
[HttpGet]
public virtual ActionResult Edit()
{
Institution inst = _service.GetInstitution(State.GetInstitutionRecordId());
_model = GetObject<SelectedAdditionalQuestionAnswerModel>();
_model.AddQuestAnswModel = new List<AdditionalQuestionAnswerModel>();
GetPageConfiguration1(inst);
return View(_model);
}
AdditionalQuestionAnswerModel m = GetObject<AdditionalQuestionAnswerModel>();
int c = 0;
foreach (var x in inst.AdditionalQuestions)
{
foreach (var y in x.AdditionalQuestionAnswers)
{
// Error is happening on next line *************
_model.AddQuestAnswModel[c].QuestionText = x.QuestionText;
_model.AddQuestAnswModel[c].InstitutionId = x.InstitutionId;
_model.AddQuestAnswModel[c].AdditionalQuestionId = x.Id;
_model.AddQuestAnswModel[c].AnswerText = y.AnswerText;
_model.AddQuestAnswModel[c].IsSelected = false;
c++;
}
}
You can't use _model.AddQuestAnswModel[c] because you never added any items to your list.
Instead of that, create a new object and set its values and then add the item to your list.
Something like this:
AdditionalQuestionAnswerModel newItem = new AdditionalQuestionAnswerModel();
//set the values here to newItem
_model.AddQuestAnswModel.Add(newItem);
You're firstly instantiating your list
_model.AddQuestAnswModel = new List<AdditionalQuestionAnswerModel>();
then you try to access to the first element
_model.AddQuestAnswModel[c] // c == 0
without adding any element to the list.
Add an element before trying to access to a list by index, or more simple:
foreach (var y in x.AdditionalQuestionAnswers)
{
AdditionalQuestionAnswerModel newObj = new AdditionalQuestionAnswerModel
{
QuestionText = x.QuestionText;
InstitutionId = x.InstitutionId;
AdditionalQuestionId = x.Id;
AnswerText = y.AnswerText;
IsSelected = false;
};
_model.AddQuestAnswModel.Add(newObj);
}
Ir means that there no item in your _model.AddQuestAnswModel at the indicated postition, and from your code, I see that _model.AddQuestAnswModel has only be initiated with new List<AdditionalQuestionAnswerModel>(), so it does not contain items (unless you're doing it in the contructor).
You need to fill it like so :
_model.AddQuestAnswModel.Add(item);