I know how to make new columns, I know how to add a header to that column, but I am a little unsure about adding values programatically.
I am going to be looping through rows and then adding values to the new columns that I create based on some functions I perform on the Data Set. I thought a good way to start would be to just pick a row and loop through it and print out all the information in that row. If I could figure out how to do that, I could probably right all the code necessary to loop through appropriate rows and get the data I need. But I am a little confused about how to use this Range object...
Range rng = (Range)wkSheet.get_Range("A1", Type.Missing);
Lets say I wanted to print out all the Range Row information to a console? How would I loop through that Range and print out that information? Even change the information in the Range. I know how to change the value of a single row, the header, but changing multiple rows is alluding me.
object[,] values = (object[,])rng.Value;
Probably duplicate reading-from-excel
Related
I have a table in an Excel worksheet where I need to programatically remove entire rows using VSTO. After a lot of searching here and everywhere else, I was unable to find the answer. Due to some unrelated code, I also cannot delete the first row of the table, but need to remove all other rows.
Here are the specific requirements:
One of the functions of this addin is to populate the table. This is done through a loop starting with the "root" named range in the left column of the first row of the table.
Whenever populating the table, I first need to delete all data from the table and then add the new data. I need to use the "root" to add the data, so I can't have it deleted.
I am using the Table for the automated formatting instead of formatting the table manually after adding each cell.
I never know how many rows will be added, but it will always be at least one.
After banging my head on this for a few hours, I slept on it and came at it refreshed this morning. After much trial and error, here is the code I came up with.
var deplTable = ThisSheet.Evaluate("DeploymentTable");
if (deplTable.ListObject.ListRows.Count > 1)
{
do deplTable.ListObject.ListRows[2].Delete();
while (deplTable.ListObject.ListRows.Count > 1);
}
NOTE: ThisSheet is set to the correct sheet earlier. The application works on multiple sheets, so it needs to be flexible.
I tried this a few ways before finally getting it to work. Looping through the rows gave unexpected results; possibly due to timing issues between Excel and VSTO.
Hope this helps other people!
I am trying to reset the number of columns in an Excel ListObject. I know you can add and remove columns one-by-one, but I want to avoid unnecessary loops. I instead decided to resize the ListObject using the Resize method.
Here is the code that I am using (where OutputCasesTable is the ListObject):
OutputCasesTable.DataBodyRange.Value2 = "";
OutputCasesTable.Resize(OutputCasesTable.Range.Resize[ColumnSize: CaseCount]);
OutputCasesTable.DataBodyRange.Value2 = OutputCasesAray;
The above lines of code appear to work perfectly, however if the ListObject only contains 1 row of data, the DataBodyRange of the ListObject becomes null on the second line - producing an error when I try to change its cell's value. The row in excel still appears to be present.
The MSDN documentation says the following:
"The header must remain in the same row and the resulting list must overlap the original list. The list must contain a header row and at least one row of data."
Now I understand that "one row of data" implies that the row contains values - so the cause of the error here must be that the DataBodyRange cells all contain no value (""). However, a table with two data rows containing "" still doesn't have a row with data, does it?
I know there are many ways of accomplishing this task, but I want to understand why this happens.
Temporary Solution:
Replaced the code to only set the values to empty strings in columns that will be removed (columns above the new column count). All other columns will be replaced:
if(OutputCasesTable.ListColumns.Count - CaseCount > 0)
OutputCasesTable.DataBodyRange.Offset[ColumnOffset: CaseCount].Resize[ColumnSize: OutputCasesTable.ListColumns.Count - CaseCount].Value2 = "";
OutputCasesTable.Resize(OutputCasesTable.Range.Resize[ColumnSize: CaseCount]);
OutputCasesTable.DataBodyRange.Value2 = OutputCasesAray;
Personally I prefer looking at the first solution!
Is there anything I can do make it work with empty strings? Or do you have a better solution?
Best regards,
The Resize operation is the piece that kills the DataBodyRange, and clearly there's some internal logic that Resize uses, along the lines of "if there is only one row, and all the cells are empty, remove all the data rows. If there is more than one row, don't remove any".
I agree that this logic is a bit confounding. If your question is why did Microsoft implement it this way, I'd argue that although it's inconsistent, it's perhaps tidier in a way - it appears to the model that you're working with an empty table, and there's no way for the model to tell the difference graphically (it's not possible for a table to just have a header row).
When Resize turns up to do its work and finds a single-row blank table, it can't tell whether you have a zero-row table or a single-row table with empty strings. If it arrives and finds two empty rows, that's unambiguous (they must be meaningful rows).
For the workaround portion of your question, I'd suggest a tidier solution of just checking the ListRows.Count property, and adding one if necessary. Note that you can also use Clear instead of setting Value2 to blank; for me it reads as more self-explanatory.
OutputCasesTable.DataBodyRange.Clear();
OutputCasesTable.Resize(OutputCasesTable.Range.Resize[ColumnSize: CaseCount]);
if (OutputCasesTable.ListRows.Count == 0) OutputCasesTable.ListRows.Add();
OutputCasesTable.DataBodyRange.Value2 = OutputCasesAray;
I have a datatable containing certain columns. I am able to display them in a repeater as a whole. However, what I want to do is to display the row, one by one. I want to create like a go next and show previous button. I did something like the following:
myDataTable.Rows.Cast<DataRow>().Take(1).CopyToDataTable();
This is giving me the first row. Now how can I use this concept to get the next row, (row 2), then row 3..... till row n. The rows being returned are different for different cases. It is an web application.
To get a different row, you just need to Skip some:
myDataTable.Rows.Cast<DataRow>().Skip(n).Take(1).CopyToDataTable();
where n is how many rows you want to skip. So, for the second record n would be 1.
I greatly disagree with the use of CopyDataDataTable(), but it would require a lot of knowledge of your code base to provide a better approach.
I would select it from the database instead, however, use Skip(n).Take(1):
var row3 = myDataTable.AsEnumerable().Skip(2).Take(1).CopyToDataTable();
Introduce the use of .Skip():
myDataTable.Rows.Cast<DataRow>().Skip(0).Take(1).CopyToDataTable();
Now you can simply track which record the user is currently viewing, and update the value sent to the .Skip() method. For example, if the user has pressed "next" 5 times, you've incremented the value 5 times:
myDataTable.Rows.Cast<DataRow>().Skip(5).Take(1).CopyToDataTable();
Keep a counter and use Skip(n-1).Take(1) for nth record.
I did a single cell subscription, so when I put the formula into the cell, it updates it correctly.
Now, I'm returning an object with multiple values and I want to display all of them in Excel cells. Is it possibly to only put a formula in 1A, subscribe once, get all values at once, and then distribute the information from one object to 1A, 1B, 1C... Or is the only way to subscribe individually to each field and put an RTD formula for every cell?
I came up with a workaround using a VBA function. Create your Excel sheet, make column headings that will match the fields that you need, put a formula in your 1A cell, and run the VBA function.
The function is just a for loop over all columns in Range (number of rows is still up to), that just gets the column header value and does your magic and the rest is up to simple string manipulation of getting the formula, converting it to string and replacing $C1 to $D1 etc.
Example:
"=RTD("ProgId", , "Your arbitrary parameter here", $C1)"
Wouldn't say it is the fastest way, but it is a good solution
How do I set the source data of an excel interop chart to several entire rows?
I have a .csv file that is created by my program to display some results that are produced. For the sake of simplicity let's say these results and chart are displayed like this: (which is exactly how I want it to be)
Now the problem I am having is that the number of people is variable. So I really need to access the entire rows data.
Right now, I am doing this:
var range = worksheet.get_range("A1","D3");
xlExcel.ActiveChart.SetSourceData(range);
and this works great if you only have three Persons, but I need to access the entire row of data.
So to restate my question, how can I set the source data of my chart to several entire rows?
I tried looking here but couldn't seem to make that work with rows instead of columns.
var range = worksheet.get_range("A1").CurrentRegion;
xlExcel.ActiveChart.SetSourceData(range);
EDIT: I am assuming that the cells in the data region won't be blank.
To test this,
1) place cursor on cell A1
2) press F5
3) click on "Special"
4) choose "Current Region" as option
5) click "OK"
This will select the cells surrounding A1 which are filled, which I believe is what you are looking for.
The translation of that in VBA code points to CurrentRegion property. I think, that should work.
Check Out the option Range.EntireRow I'm not 100% on how to expand that to a single range containing 3 entire rows, but it shouldn't be that difficult to accomplish.
Another thing you can do is scan to get the actual maximum column index you need (this is assuming that there are guaranteed to be no gaps in the names), then use that index as you declare your range.
Add Code
int c = 2;//column b
while(true)
{
if (String.IsNullOrEmpty(worksheet.GetRange(1,c).Value2))
{
c--;
break;
}
c++;
}
Take a column from A to D that you're sure has no empty cells.
Do some loop to find the first empty one in that column and it will be one after the last.
Range Cell = SHeet.Range["A1"]; //or another column you're sure there's no empty data
int LineOffset = 0;
while (Cell.Offset[LineOffset, 0].Value != "") //maybe you should cast the left side to string, not sure.
{
LineOffset++;
}
int LastLine = LineOffset - 1;
Then you can get Range[Sheet.Cells[1,1], Sheet.Cells[LastLine, 4]]
Out of the box here, but why not transpose the data? Three columns for Name, Height, Weight. Convert this from an ordinary range to a Table.
When any formula, including a chart's SERIES formula references a column of a table, it always references that column, no matter how long the table gets. Add another person (another row) and the chart displays the data with the added person. Remove a few people, and the chart adjusts without leaving blanks at the end.
This is illustrated in my tutorial, Easy Dynamic Charts Using Lists or Tables.