EPPlus LoadFromCollection always put values in one column - c#

I want to set each element of collection in one row, but they are always added in one column, not row.
var headers = new List<string> {...};
var row = 4;
worksheet.Cells[row, 2, row, headers.Count()].LoadFromCollection(headers);
From code - I select Range in what I want to load collection. But it doesn't work as expected. Result in image (Dates should be in row as column headers).
Using EPPlus version 4.5.3.2

LoadFromCollection is supposed to work like that. Normally you pass it a collection of a complex type, then the properties of that type become the column headers, while each item in the collection is populated on a separate row.
Since you're passing a simple type, it's just like you passed a complex type with a single property. Every value goes on a different row.
If you instead want the items in your collection to be on the same row, just write a for loop to iterate over the items in the collection and add them.

Related

empty a specific column of numbers from the datagridview

Question:
How to empty specific column of numbers from datagridview? (i mean erase the values without header, not delete the column).
for example FROM THIS TO THAT, so i dont need to do it manually
How i created the datagridview:
i created a database table, with 5 ID's all of datatype "int", i connected the datagridview through DataSource, bindingsource. And when i put values in the table and press button:(button code below)
table1BindingSource2.EndEdit();
table1TableAdapter2.Update(database1DataSet8.Table1;
It will save the values into DataTable.
For example the first ID in the table is : Konduktivita1[µS_cm-1]
What i think is neccesery is to actually delete the values from DataTable but i dont how to do it.
It would be easier if you provided some kind of code, but let's try something like this.
var sourceList = dataGridName.ItemsSource as List<sqlTable>; //or whatever your data is called
foreach (var item in sourceList)
{
item.Konduktiva1 = null; // or 0
}

How do you get all X objects in all Y objects?

I got a class named Sheet, with a List containing Row objects. Each Row object has a List containing Cell objects. Now I want to implement a Sheet.Cells property that returns all cells on all rows. I'm sure there must be an elegant LINQ solution for this, but haven't been able to figure it out. Assuming I got all rows in this.rows, how do I use LINQ to get an IEnumerable containing all cells in all rows?
IEnumerable<Cell> cells = this.rows ...?
There is, called SelectMany:
IEnumerable<Cell> cells = this.rows.SelectMany(r => r.Cells);

Using Excel interop to retrieve information from the range that meet criteria

oSheet = (Excel._Worksheet)xlWorkBook.ActiveSheet;
oRng = oSheet.get_Range("T10", "T343");
The range oRng contains values of type double. Each cell in Column T shows the max number of the associated row. How can i find out how many 1’s , 2’s 3’s ….. till 10 are in that range. Secondly Eg if there are 20 rows with value =3 , I need to copy column A,B,C from those rows and store them for later use .i need the count of the number of rows for each value from 1 to 10
Here are a few general observations that might be enough to get you going:
Excel.Range has an AutoFilter method that you might be able to employ successively for each value that you're interested in (i.e, 1 through 10). Once you have the individual ranges returned by AutoFilter, you can them query them for the specific information you're interested in. See C# Excel Automation: Retrieving rows after AutoFilter() with SpecialCells() does not seem to work properly for issues associated with this approach.
Alternatively, you might be able to do something like create a simple dictionary that you could then populate as you iterate over column T. For example, the dictionary could be of type Dictionary>.
As you proceed through column T, you encounter a value in each cell. If the cell value hasn't been seen before, you add it as a new key to the Dictionary. For the associated value in the dictionary's key/value pair, you create a new List with the corresponding row number as its first element.
If the cell value has been seen before, you look it up in the dictionary, then add the corresponding row to the List associated with that key.
At the end of the day, your dictionary's keys contains all the values found in column T. The number of rows associated with each value is just the number of elements in the associated List. With the row values in the List, you can then find "A[row value]", "B[row value]" and "C[row value]".

Is there a more efficient way to create lists that are the same?

I have a series of lists and classes that implement a table of data. The basic classes are: Columns, Rows, and Cells. The Rows contains some ID information and list of Cells which contains the row's value for each column. Currently I create the rows in a cell with code like this
void CreateRow()
{
Row newRow = new Row();
newRow.ID = idInfo;
foreach (var Column in Columns)
{
newRow.Cells.Add(new Cell(Column.ID));
}
Rows.Add(newRow);
}
The works fine, but in some cases am calling CreateRow() 20,000 times and have 200+ columns. So I am wondering if there is a more efficient way to populate the cells since the cells in a certain column in each row are identical.
Any ideas?
Thanks,
Jerry
Currently you create unique Cell object for each position in your matrix - that's a lot of cells given your use case of 20.000 + rows.
One approach to be more efficient could be to not add the cells at all when you construct the matrix, but only when you try to get or set its value (i.e using Lazy<T>).
Assuming you set the value of a cell before retrieving it, you could then have a factory method for creating a cell with a value - make the Cell object immutable and when you are "creating" a Cell for which you already have another cell with an identical value, return that cell instead. This could reduce the total number of Cell objects significantly, of course there's more overhead since you need to check whether you have a cell of the same value already and need to call the factory method again if you need to update the value of a cell.
Then again all of this could not be worth it if you do not experience any memory/performance problems with your current approach - measuring performance is key here.
Isn't Columns a collection?
var Ids = Columns.Select(c => c.Id).ToArray();
var Names = Columns.Select(c => c.Name).ToArray();
etc. Except why do that if Columns is already a collection? For you could do Columns[index].Id
Or if you must have the code you outlined:
Row newRow = new Row();
newRow.ID = idInfo;
// presuming Cells is a List<>
newRow.Cells.AddRange(Columns.Select(c => new Cell(c.Id)));
Rows.Add(newRow);
Some suggestions (depends on what you are looking for)
Consider using (strongly typed) DataSet/DataTable
If using List and you know the size, set the capacity to avoid reallocation (new List(2000))
Use struct instead of class if it makes sense
Cache objects if it makes sense (instead of duplicating the same object over and over)
You're creating the cells anyways. So I gather that the question refers to when you will fill the cells with their values, which are always in each column for all rows.
I actually think that from a correctness point of view, it makes sense to have the data duplicated, since they are in effect separate instances of the same data.
That said, if it is not really data, but you just want to show a view-column with the same value for each row, and you just want it as a data column in order to ease showing it as a view-column, then in your property-get Row.Cells(Id) you can check the ID, and if it's one of those columns where the value is always the same, return that value, bypassing looking up your _Cells collection.
If the data is mostly the same and sometimes different, you may want to use 'default values' where if the Cell object does not exist, a default value for that column will be returned. This necessitates a GetValue() method on the row, though, if you want to avoid having the Cell object altogether for places where it is default.
If you don't care about #1, you can really make a single instance of whatever the value is, and reference it in your Cell's value. This is harder to do for a Value Type than for a Reference Type (definition here) but it can be done.
Lastly, is there any reason you're not using .NET's supplied DataTable and DataRow types? I'm sure the MS geeks programmed as much efficiency as they could into those.

Counting the number of unique image occurences in a DataGridViewImageColumn

In a DataGridView bound to a DataView, where cells in a column will contain one of two images from an ImageList (e.g. a green 'online' image or a red 'offline' image), how can you sum the number of occurences of each image when iterating through the DataGridView's rows?
The Value and FormattedValue properties of DataGridViewImageCell return different references even though the entries in the underlying DataTable were created by referencing the same Image from the ImageList.
So rather than it counting 4 occurences of 'online' and 6 occurences of 'offline', I'm getting 10 occurences of alledgedly different images.
Given the description, the best I can suggest is to manually track the image key/index in the .Tag of the cell, and then run your distinct count on the .Tag. Alternatively, if you also have the data in a list/collection, count the data from the original source.
[update following reply]
Since the data is data-bound, you should be able to iterate the .Rows of the DataGridView, obtaining the .DataBoundItem of each. Then for each underlying object, you should be able to obtain the actual property value using TypeDescriptor:
string propName = col.DataPropertyName;
// could also be a dictionary/hashset etc
// could be typed if you know the type
List<object> values = new List<object>();
foreach(DataGridViewRow row in dgv.Rows)
{
object obj = row.DataBoundItem;
// could be typed (via cast) if you know the type
object val = TypeDescriptor.GetProperties(obj)[propName].GetValue(obj);
if (!values.Contains(val))
{
values.Add(val);
}
}
That any help?

Categories