Consider this code:
var dropDown = sheet.DataValidations.AddListValidation(cells[2, colIndex, maxCol, colIndex].Address);
foreach (var bb in brokerBranchs)
{
dropDown.Formula.Values.Add(bb.Title);
}
With 29 of dropDown items everything is ok and created excel file works fine but as the number of items exceeds 29, opening created file shows following error:
Opening corrupted result file discards all drop down items associated with all columns.
What is possible solution to this problem? Any help will be appreciated.
you must add new sheet to add drop down item insert to this sheet
ExcelWorksheet ddList = excelPackage.Workbook.Worksheets.Add("DropDownList");
now add data to ddList in first column
var brokerBranchs = accountingUnitOfWork.BrokerServiceAccessor.GetBrokerBranchByBrokerId(firmId).OrderBy(x => x.Title).ToList();
var val = sheet.DataValidations.AddListValidation(cells[2, colIndex, maxCol, colIndex].Address);
for (int index = 1; index <= brokerBranchs.Count; index++)
{
ddList.Cells[index, 1].Value = brokerBranchs[index - 1].Title;
}
now create address for use in formula
var address = ddList.Cells[1, 1, brokerBranchs.Count(), 1].Address.ToString();
var arr = address.Split(':');
var char1 = arr[0][0];
var num1 = arr[0].Trim(char1);
var char2 = arr[1][0];
var num2 = arr[1].Trim(char2);
now use address in formula
val.Formula.ExcelFormula = string.Format("=DropDownList!${0}${1}:${2}${3}", char1, num1, char2, num2);
val.ShowErrorMessage = true;
val.Error = "Select from List of Values ...";
Related
I'm trying to add values to a IExcelDataValidationList but the way I'm doing it right now is not very efficient.
I need to create many rows in my worksheet and populate a list for a certain cell for each of these rows. When I have many values to add to the list, this is taking forever.
for (var x = headerRowIndex + 1; x < 1000; x++)
{
var address = ExcelCellBase.TranslateFromR1C1($"R{x}C{colIndex}", 0, 0);
IExcelDataValidationList list = mainWorksheet.DataValidations.AddListValidation(address);
foreach (var e in values)
{
list.Formula.Values.Add(e);
}
}
You see how this can take a long time if values contain a lot of options.
Here's what I tried:
List<string> validationValues = new List<string>();
validationValues = values.ToList();
for (var x = headerRowIndex + 1; x < 1000; x++)
{
var address = ExcelCellBase.TranslateFromR1C1($"R{x}C{colIndex}", 0, 0);
var list = mainWorksheet.DataValidations.AddListValidation(address);
((List<string>)list.Formula.Values).AddRange(validationValues);
}
So I'm trying to add all values to the list at once. This compiles fine, but I'm getting this exception:
System.InvalidCastException: 'Unable to cast object of type
'DataValidationList' to type
'System.Collections.Generic.List`1[System.String]'.'
I've tried casting directly to DataValidationList but it's defined at private and only accessible by EPPlus itself.
Any ideas ?
Instead of creating IExcelDataValidationList per cell, create one for the whole column (address can include range of cells):
var address = ExcelCellBase.GetAddress(headerRowIndex + 1, colIndex, headerRowIndex + 1000, colIndex, true); // whole column
IExcelDataValidationList list = mainWorksheet.DataValidations.AddListValidation(address);
foreach (var e in values)
{
list.Formula.Values.Add(e);
}
I am making a program in Visual Studio where you can read in an excel file in a specific format and where my program converts the data from the excel file in a different format and stores it in a database table.
Below you can find a part of my code where something strange happens
//copy schema into new datatable
DataTable _longDataTable = _library.Clone();
foreach (DataRow drlibrary in _library.Rows)
{
//count number of variables in a row
string check = drlibrary["Check"].ToString();
int varCount = check.Length - check.Replace("{", "").Length;
int count_and = 0;
if (check.Contains("and") || check.Contains("or"))
{
count_and = Regex.Matches(check, "and").Count;
varCount = varCount - count_and;
}
//loop through number of counted variables in order to add rows to long datatable (one row per variable)
for (int i = 1; i <= varCount; i++)
{
var newRow = _longDataTable.NewRow();
newRow.ItemArray = drlibrary.ItemArray;
string j = i.ToString();
//fill variablename with variable number
if (i < 10)
{
newRow["VariableName"] = "Variable0" + j;
}
else
{
newRow["VariableName"] = "Variable" + j;
}
}
}
When varCount equals 1, I get the following error message when running the program after inserting an excel file
The source contains no DataRows.
I don't know why I can't run the for loop with just one iteration. Anyone who can help me?
how can we read all lines from notepad comma separated and updated specific column conditionally, its successfully iterating no error is coming but not to update the value in C#
string[] existingLines = File.ReadAllLines(filepath);
foreach (var row in existingLines)
{
row.Split(Text_Separator)[0] = "Test Data";
}
var newdata = existingLines;
You'll need to use a for loop to modify an item while iterating over it. I believe you'll get an error if using foreach. This is because you are exposing an enumerator which is read-only.
This will iterate through each row, modify a column and replace the current row.
string[] existingLines = File.ReadAllLines(filepath);
foreach (var i = 0; i < existingLines.Length; i++)
{
// retrieve row by index
var row = existingLines[i];
// split into array of columns
var columns = row.Split(Text_Separator);
// update column
columns[0] = "Test Data";
// create row from array of columns
var updatedRow = string.Join(Text_Separator, columns);
// update row in array of rows
existingLines[i] = updatedRow;
}
var newdata = existingLines;
String.Split method will create a new instance of string array which is not referred to the existingLines variable. Hence, updating the value returned from Split does not reflect on existingLines
String[] stringArray = splitStrings;
if( arrIndex!= maxItems) {
stringArray = new String[arrIndex];
for( int j = 0; j < arrIndex; j++) {
stringArray[j] = splitStrings[j];
}
}
return stringArray;
https://github.com/Microsoft/referencesource/blob/master/mscorlib/system/string.cs
I am getting a list of items from a csv file via a Web Api using this code:
private List<Item> items = new List<Item>();
public ItemRepository()
{
string filename = HttpRuntime.AppDomainAppPath + "App_Data\\items.csv";
var lines = File.ReadAllLines(filename).Skip(1).ToList();
for (int i = 0; i < lines.Count; i++)
{
var line = lines[i];
var columns = line.Split('$');
//get rid of newline characters in the middle of data lines
while (columns.Length < 9)
{
i += 1;
line = line.Replace("\n", " ") + lines[i];
columns = line.Split('$');
}
//Remove Starting and Trailing open quotes from fields
columns = columns.Select(c => { if (string.IsNullOrEmpty(c) == false) { return c.Substring(1, c.Length - 2); } return string.Empty; }).ToArray();
var temp = columns[5].Split('|', '>');
items.Add(new Item()
{
Id = int.Parse(columns[0]),
Name = temp[0],
Description = columns[2],
Photo = columns[7]
});
}
}
The Name attribute of the item list must come from column whose structure is as follows:
Groups>Subgroup>item
Therefore I use var temp = columns[5].Split('|', '>'); in my code to get the first element of the column before the ">", which in the above case is Groups. And this works fine.
However, I a getting many duplicates in the result. This is because other items in the column may be:
(These are some of the entries in my csv column 9)
Groups>Subgroup2>item2, Groups>Subgroup3>item4, Groups>Subgroup4>item9
All start with Groups, but I only want to get Groups once.
As it is I get a long list of Groups. How do I stop the duplicates?
I want that if an Item in the list is returned with the Name "Groups", that no other item with that name would be returned. How do I make this check and implement it?
If you are successfully getting the list of groups, take that list of groups and use LINQ:
var undupedList = dupedList
.Distinct();
Update: The reason distinct did not work is because your code is requesting not just Name, but also, Description, etc...If you only ask for Name, Distinct() will work.
Update 2: Try this:
//Check whether already exists
if((var match = items.Where(q=>q.Name == temp[0])).Count==0)
{
items.add(...);
}
How about using a List to store Item.Name?
Then check List.Contains() before calling items.Add()
Simple, only 3 lines of code, and it works.
IList<string> listNames = new List();
//
for (int i = 0; i < lines.Count; i++)
{
//
var temp = columns[5].Split('|', '>');
if (!listNames.Contains(temp[0]))
{
listNames.Add(temp[0]);
items.Add(new Item()
{
//
});
}
}
I'm entering data from a CSV file into a OpenOffice spreadsheet.
This code gets the a new sheet in a spreadsheet:
Public Spreadsheet getSpreadsheet(int sheetIndex, XComponent xComp)
{
XSpreadsheet xSheets = ((XSpreadsheetDocument)xComp).getSheets();
XIndexAccess xSheetIA = (XIndexAccess)xSheets;
XSpreadsheet XSheet = (XSpreadsheet)xSheetsA.getByIndex(sheetIndex).Value;
return XSheet;
}
I then have method that enters a list into a cell range one cell at a time. I want to be able to automatically set the column size for these cells. which is something like
string final DataCell;
Xspreadsheet newSheet = getSpreadsheet(sheetIndex, xComp);
int numberOfRecords = ( int numberOfColumns * int numberOfRows);
for(cellNumber = 0; cellNumber < numberOfrecords; cellNumber++)
{
XCell tableData = newSheet.getCellbyPosition(columnValue, rowValue);
((XText)tableData).setString(finalDataCell);
column Value++;
if(columnValue > = numberOfColumns)
{
rowVal++ column = 0;
}
}
After googling i have found the function:
columns.OptimalWidth = True on http://forum.openoffice.org/en/forum/viewtopic.php?f=20&t=31292
but im unsure on how to use this. Could anyone explain this further or think of another way to have the cell autofit?
I understand the comments in the code are in Spanish I think, but the code is in English. I ran the comments through Google translate so now they are in English. I copied it from here:
//Auto Enlarge col width
private void largeurAuto(string NomCol)
{
XCellRange Range = null;
Range = Sheet.getCellRangeByName(NomCol + "1"); //Recover the range, a cell is
XColumnRowRange RCol = (XColumnRowRange)Range; //Creates a collar ranks
XTableColumns LCol = RCol.getColumns(); // Retrieves the list of passes
uno.Any Col = LCol.getByIndex(0); //Extract the first Col
XPropertySet xPropSet = (XPropertySet)Col.Value;
xPropSet.setPropertyValue("OptimalWidth", new one.Any((bool)true));
}
What this does it this: First it gets the range name and then gets the first column. The real code, though, is XpropertySet being used, which is explained REALLY well here.
public void optimalWidth(XSpreadsheet newSheet)
{
// gets the used range of the sheet
XSheetCellCursor XCursor = newSheet.createCursor();
XUsedAreaCursor xUsedCursor = (XUsedAreaCursor)XCursor;
xUsedCursor.gotoStartOfUsedArea(true);
xUsedCursor.gotoEndOfUsedArea(true);
XCellRangeAddressable nomCol = (XCellRangeAddressable)xUsedCursor;
XColumnRowRange RCol = (XColumnRowRange)nomCol;
XTableColumns LCol = RCol.getColumns();
// loops round all of the columns
for (int i = 0; i < nomCol.getRangeAddress().EndColumn;i++)
{
XPropertySet xPropSet = (XPropertySet)LCol.getByIndex(i).Value;
xPropSet.setPropertyValue("OptimalWidth", new uno.Any(true));
}
}