如何使用Excel.Range.set_Value()指定单个单元格的格式
当我把整个表格写入一个excel工作表时,我知道要一次处理整个范围,而不是写入单个单元格。 然而,有没有办法指定格式,因为我正在填充我要导出到Excel的数组?
以下是我现在所做的:
object MissingValue = System.Reflection.Missing.Value; Excel.Application excel = new Excel.Application(); int rows = 5; int cols = 5; int someVal; Excel.Worksheet sheet = (Excel.Worksheet)excel.Workbooks.Add(MissingValue).Sheets[1]; Excel.Range range = sheet.Range("A1", sheet.Cells(rows,cols)); object[,] rangeData = new object[rows,cols]; for(int r = 0; r < rows; r++) { for(int c = 0; c < cols; c++) { someVal = r + c; rangeData[r,c] = someVal.ToString(); } } range.set_Value(MissingValue, rangeData);
现在假设我想将这些数字中的一部分格式化为百分比。 我知道我可以回到一个单元格的基础上,改变格式,但这似乎打败了使用单个Range.set_Value()调用的全部目的。 我可以使我的rangeData [,]结构包含格式化信息,以便当我调用set_Value()时,单元格的格式是否符合我的要求?
为了澄清,我知道我可以设置整个Excel.Range对象的格式。 我想要的是为每个单元指定不同的格式,在内部循环中指定。
您可以在范围上应用格式,然后使用您无法在object[,]
指定格式的值填充object[,]
数组
所以这是迄今为止我发现的最好的“解决scheme”。 这不是我正在寻找的天堂,但它比单独设置每个单元的格式要快得多。
// 0-based indexes static string RcToA1(int row, int col) { string toRet = ""; int mag = 0; while(col >= Math.Pow(26, mag+1)){mag++;} while (mag>0) { toRet += System.Convert.ToChar(64 + (byte)Math.Truncate((double)(col/(Math.Pow(26,mag))))); col -= (int)Math.Truncate((double)Math.Pow(26, mag--)); } toRet += System.Convert.ToChar(65 + col); return toRet + (row + 1).ToString(); } static Random rand = new Random(DateTime.Now.Millisecond); static string RandomExcelFormat() { switch ((int)Math.Round(rand.NextDouble(),0)) { case 0: return "0.00%"; default: return "0.00"; } } struct ExcelFormatSpecifier { public object NumberFormat; public string RangeAddress; } static void DoWork() { List<ExcelFormatSpecifier> NumberFormatList = new List<ExcelFormatSpecifier>(0); object[,] rangeData = new object[rows,cols]; for(int r = 0; r < rows; r++) { for(int c = 0; c < cols; c++) { someVal = r + c; rangeData[r,c] = someVal.ToString(); NumberFormatList.Add(new ExcelFormatSpecifier { NumberFormat = RandomExcelFormat(), RangeAddress = RcToA1(rowIndex, colIndex) }); } } range.set_Value(MissingValue, rangeData); int max_format = 50; foreach (string formatSpecifier in NumberFormatList.Select(p => p.NumberFormat).Distinct()) { List<string> addresses = NumberFormatList.Where(p => p.NumberFormat == formatSpecifier).Select(p => p.RangeAddress).ToList(); while (addresses.Count > 0) { string addressSpecifier = string.Join(",", addresses.Take(max_format).ToArray()); range.get_Range(addressSpecifier, MissingValue).NumberFormat = formatSpecifier; addresses = addresses.Skip(max_format).ToList(); } } }
基本上,发生的事情是,我在NumberFormatList中保存每个单元格的格式信息列表(每个元素也包含它所适用的范围的A1样式的地址)。 最初的想法是,对于工作表中的每种不同的格式,我应该能够构build一个只有这些单元格的Excel.Range,并在一次调用中将该格式应用于该范围。 这将会减less从Number(可能)到NumberFormat的访问次数到less数几个(但是有很多不同的格式)。
然而,我遇到了一个问题,因为你显然不能从一个任意长的单元格列表中构build一个范围。 经过一些testing后,我发现极限值在50到100个单元格之间,可以用来定义一个任意范围(如range.get_Range(“A1,B1,C1,A2,AA5,…”) 。所以一旦我得到所有单元格的列表来应用格式,我有一个最后的while()循环,一次将格式应用到50个单元格。
这是不理想的,但它仍然减less了对NumberFormat访问的数量高达50,这是显着的。 构造没有任何格式信息的电子表格(仅使用range.set_Value())大约需要3秒。 当我一次应用50格的格式时,这个格式被延长到10秒左右。 当我将格式信息分别应用于每个单元格时,电子表格需要2分钟才能完成构build!
您可以将格式应用于内部循环中的每个单独的单元格
for(int r = 0; r < rows; r++) { for(int c = 0; c < cols; c++) { Excel.Range r2 = sheet.Cells( r, c ); r2.xxxx = ""; } }
一旦你有r2
,你可以任何你想要的方式改变单元格格式。