Итак, вот лучшее «решение», которое я нашел до сих пор. Это не та нирванна, которую я искал, но она намного, намного быстрее, чем настройка формата для каждой ячейки отдельно.
// 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 диапазона, к которому он применяется). Первоначальная идея заключалась в том, что для каждого отдельного формата на рабочем листе я должен иметь возможность создать Excel.Range только из этих ячеек и применить формат к этому диапазону за один вызов. Это уменьшит количество обращений к NumberFormat с (потенциально) тысяч до нескольких (сколь угодно разных форматов).
Однако я столкнулся с проблемой, потому что вы, очевидно, не можете построить диапазон из произвольно длинного списка ячеек. После некоторого тестирования я обнаружил, что предел находится где-то между 50 и 100 ячейками, которые можно использовать для определения произвольного диапазона (как в range.get_Range («A1, B1, C1, A2, AA5, .....») Поэтому, как только я получил список всех ячеек, к которым нужно применить формат, у меня есть один последний цикл while (), который применяет формат к 50 из этих ячеек одновременно.
Это не идеально, но все равно уменьшает количество обращений к NumberFormat до 50 раз, что существенно. Создание моей таблицы без какой-либо информации о формате (только с использованием range.set_Value ()) занимает около 3 секунд. Когда я применяю форматы по 50 ячеек за раз, это удлиняется примерно до 10 секунд. Когда я применяю информацию о формате отдельно к каждой ячейке, создание таблицы занимает более 2 минут!