I have 2 lists..
The first contains rows with mapping values inlcuding column name, xcord, ycord
The second contains the data I need to map..
I need to get the value in each row using the column name from the first row..
for example
List<SheetMappings> smaps = new List<SheetMappings>();
foreach(maplist m in mlist)
{
SheetMappings newMap = new SheetMappings();
foreach(vallist v in vlist)
{
newMap.Value = v.{m.ColumnName};
newMap.xCord = m.xCord;
newMap.yCord = m.yCord;
}
smaps.Add(newMap);
}
Any assitance appreciated
Cheers
Graham
EDIT:
List<SpreadMappings> spreadMapping = new List<SpreadMappings>();
foreach (var m in mappings)
{
foreach (var v in hvalues)
{
SpreadMappings map = new SpreadMappings();
switch (m.ColumnName)
{
case “DocHeading”:
map.ColumnX = m.ColumnX;
map.ColumnY = m.ColumnY;
map.ColumnValue = v.DocHeading;
map.ColumnName = m.ColumnName;
map.ColumnId = v.Id;
map.ColumnSheetName = sheetName; spreadMapping.Add(map);
break;
If I understand what you're trying to do, you'll need to use reflection to get the value of the property represented by m.ColumnName:
var smaps = new List<SheetMappings>();
foreach(maplist m in mlist)
{
var pi = typeof(vallist).GetProperty(m.ColumnName);
var newMap = new SheetMappings();
foreach(vallist v in vlist)
{
newMap.Value = pi.GetValue(v, null);
newMap.xCord = m.xCord;
newMap.yCord = m.yCord;
}
smaps.Add(newMap);
}
So that's using reflection to get a reference to the PropertyInfo for the property represented by m.ColumnName, then calling PropertyInfo.GetValue to get the value of that property from v.
Well I think the "newMap.Value = v.{m.ColumnName}" part would be something like:
newMap.Value = v.FirstOrDefault( vitem => vitem.ColumnName == m.ColumnName );
This would give you the first item within "v" that has a "ColumnName" property that matches the "ColumnName" property of "m". This assumes that the contents of "vallist" are objects that have a "ColumnName" property.
Related
I have found a way how to display the list without diacritic but how to display it with diacritic ? Here I am checking if the value is in the list twice, if it is then I need to display the one with diacritic but how do I check for diacritic?
{
var fields = new List<Field>()
{
new Field{ Value ="Kateřina Kučerová", IdentityDocumentFieldType = IdentityDocumentFieldType.unknown},
new Field{ Value = "Katerina Kucerova", IdentityDocumentFieldType = IdentityDocumentFieldType.Document},
};
foreach (var field in fields)
{
var value = field.Value;
//Console.WriteLine(StringExtenstion.RemoveDiacritics(value));
var exists = fields.Any(r => r.Desc == field.Desc);
if (!exists)
{
Console.WriteLine(field.Value);
}
else
{
Console.WriteLine(field.Value);
}
}}
string input =#"Kateřina Kučerová";
var samo = "řčěáíéě";
foreach (char c in samo)
{
if(input.Contains(c))
Console.WriteLine("ok");
}
This is what I needed
I have the following looping foreach in list. I would like to know how I can write this in lambda expression as part of my learning.
int count = 0;
foreach (var c in result)
{
response.AllChecklist[0].obj.Name = c.Name;
response.AllChecklist[0].obj.Category = c.Category;
response.AllChecklist[0].obj.Code = c.Code;
response.AllChecklist[0].obj.chk[count].Name = c.Name;
response.AllChecklist[0].obj.chk[count].Type = c.Type;
response.AllChecklist[0].obj.chk[count].chktatusCode = c.chktatusCode;
response.AllChecklist[0].obj.chk[count].chktatusReasonCode = c.chktatusReasonCode;
count++;
}
Should I have to write like this result.ForEach()
I need to know the type of chk. I will assume its a class called Chk
response.AllCheckList[0].obj.chk = result.Select(r=>
new Chk{
Name = r.Name,
Type = r.Type,
chkStatusCode = r.chkStatusCode,
chkStatusReason = r.chkStatusReason
}).ToArray();
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 have a IEnumerable<object> dataSource which contains a collection anonymous types. The actual structure of the anonymous type won't be known at design time, so I'm trying to find a generic solution that can handle any anonymous type.
How can I load them into epplus to create a spreadsheet? I have a worksheet called ws and I tried:
ws.Cells["A1"].LoadFromCollection(dataSource, true);
However when that runs it outputs all of the anonymous type's properties into a single cell:
{ Id = 10000, Title = This is a test }
I've tried passing in MemberInfo using:
var members = dataSource.First().GetType().GetMembers();
ws.Cells["A1"].LoadFromCollection(this._dataSource, true,
TableStyles.Medium1, BindingFlags.Public, members);
But that throws an exception:
Supplied properties in parameter Properties must be of the same type as T
Any suggestions on how I can create a spreadsheet using anonymous types in c#?
I have tested
using (var excel = new OfficeOpenXml.ExcelPackage())
{
var sheet = excel.Workbook.Worksheets.Add("Test");
sheet.Cells["A1"].LoadFromCollection(dataSource, true);
excel.SaveAs(new FileInfo(#"C:\Temp\Test.xlsx"));
}
with this sample data:
var dataSource = Enumerable.Range(1, 100).Select(i => new{ ID=i, Title="Title " + i });
It works fine. It creates two columns with the correct headers and 100 rows.
But you should use anonymous types only if you know the structure at compile time.
You could use a DataTable and LoadFromDataTable instead. Since i don't know how you create the anonymous type i show you just a small sample:
DataTable dataSource = new DataTable();
dataSource.Columns.Add("Id"); // default type is string
dataSource.Columns.Add("Title");
// add other columns
dataSource.Rows.Add("1", "Title1");
// add other rows
using (var excel = new OfficeOpenXml.ExcelPackage())
{
var sheet = excel.Workbook.Worksheets.Add("Test");
sheet.Cells["A1"].LoadFromDataTable(dataSource, true);
excel.SaveAs(new FileInfo(#"C:\Temp\Test.xlsx"));
}
You could group the anonymous types to make it easier for exporting with dataTables. The bug "Supplied properties in parameter Properties must be of the same type as T" is still there and a workaround is using DataTables.
// Imagine list is your main datasource
IEnumerable<object> list = Enumerable.Empty<object>(); // Data Source of <object>
// Added anon types at runtime added to the object list
var anonTypesOne = new object[]
{
new { GuidID = Guid.NewGuid(), StringProperty = "the string property" },
new { IntegerID = 1, IntegerProperty = 99 }
};
var anonTypesTwo = new object[]
{
new { StringID = "1", BooleanProperty = true, NumberProperty = 3, StringProperty = "Four" },
new { GuidID = Guid.NewGuid(), NumberThree = 3 },
new { GuidID = Guid.NewGuid(), NumberThree = 3 },
new { GuidID = Guid.NewGuid(), NumberThree = 3 }
};
list = list.Concat(anonTypesOne).Concat(anonTypesTwo);
// Grouping works on anon types so we can group the export into their own tables
var groupings = list.GroupBy(i => i.GetType());
using(var package = new ExcelPackage(new FileInfo("C:\\Temp\\Anon.xlsx")))
{
var ws = package.Workbook.Worksheets.Add("Anonymous Types");
// add each "anon type matched grouping"
foreach(var grouping in groupings)
{
var isNew = ws.Dimension == null; // the sheet is empty if Dimension is null.
var row = 0;
if(isNew)
{
row = 1; // start from the first row
}
else
{
// otherwise there are tables already, start from the bottom
row = ws.Dimension.End.Row;
}
// because of EPP inheritance bug of T, we can just use dataTable
DataTable dt = new DataTable(grouping.Key.Name);
var properties = grouping.Key.GetProperties(); // Get anon type Properties
foreach(var property in properties)
{
dt.Columns.Add(property.Name);
}
foreach(var item in grouping.ToList())
{
var dataRow = dt.NewRow();
foreach(var p in properties) // populate a single row
{
dataRow[p.Name] = p.GetValue(item); // item is anon object instance
}
dt.Rows.Add(dataRow);
}
if(isNew) // load into the top most left cell of the worksheet
ws.Cells[1, 1].LoadFromDataTable(dt, PrintHeaders: true);
else // load from the dimension of current items + 1 row for spacing
ws.Cells[ws.Dimension.End.Row + 1, 1].LoadFromDataTable(dt, PrintHeaders: true);
ws.InsertRow(ws.Dimension.End.Row + 2, 5); // Insert some padding between each group
}
package.Save();
}
I was, this thread is older, but I'm looking for the same problem.
With the following code (VB) I have success.
Carsten
Dim targetFile = New IO.FileInfo(sFN)
Dim dataSource = Enumerable.Range(0, 1).Select(Function(i) New With {.ID = 1000, .Titel = "This is a test "}).ToList
Using epp = New OfficeOpenXml.ExcelPackage(targetFile)
Dim ws = epp.Workbook.Worksheets.Add("lst_Anonymous")
ws.Cells(1, 1).LoadFromCollection(dataSource, True,
OfficeOpenXml.Table.TableStyles.Medium1,
Reflection.BindingFlags.Public,
dataSource.GetType.GetGenericArguments()(0).GetProperties)
epp.Save()
End Using
Want to use a variable based on its name. It is hard to describe. Here is the example
var sections = new[] { "Personnel", "General", "Medical" };
foreach (var s in sections)
{
// want to retrieve the variable "lblPersonnel"
(Label)Type.GetType(string.Format("lbl{0}", s)).Text = "Test";
}
so that we don't have to :
lblPersonnel.Text = "Test";
lblGeneral.Text = "Test";
lblMedical.Text = "Test";
So, is it possible for this kind of "reflection"?
Type.GetType expects a fully-qualified type name but you are trying to pass it name of the variable.And also it returns a Type instance so you can't cast it to Label.It seems you are confused about types,instances and variables. If you have labels and you want to access them you can use Controls collection of your Form.
foreach (var s in sections)
{
var name = string.Format("lbl{0}", s);
if(this.Controls.ContainsKey(name))
{
var currentLabel = this.Controls[name] as Label;
if(currentLabel != null) currentLabel.Text = "Test";
}
}
Edit: If you are devoloping an ASP.NET project then you can use FindControl method to get your labels by name:
foreach (var s in sections)
{
var name = string.Format("lbl{0}", s);
var currentLabel = FindControl(name) as Label;
if(currentLabel != null) currentLabel.Text = "Test";
}
Why not just get the label using Controls?
var sections = new [] {"Personnel", "General", "Medical"};
foreach (var s in sections)
{
// want to retrieve the variable "lblPersonnel"
((Label)(Controls["lbl" + s])).Text = "Test";
}
foreach (var s in sections)
{
string name = string.Format("lbl{0}", s);
FieldInfo fi = typeof(Form1).GetField(name);
Label l = (Label)(fi.GetValue(this));
l.Text = "Test";
}
This is assuming the Labels are public fields. If they are properties - use GetProperty , if they are private fields, use:
GetField(name, BindingFlags.NonPublic | BindingFlags.Instance);