Как установить значения в двумерном диапазоне Excel?

Мне нужно создать лист Excel из списка тестовых случаев в определенном формате, чтобы загрузить его на сервер. У меня есть проблемы с заполнением двухмерного диапазона "ожидаемого" и "фактического" в файле. Я использую те же методы, чтобы заполнить заголовки, которые являются одномерным массивом, и шаги (которые являются двухцветными).

Поток это:

  1. Защита диапазона TestCase (некоторые заголовки + шаги). Допустим, от А1 до Е14 для 1-й итерации.
  2. Depunding под (локальный) диапазон в пределах диапазона testCase для заголовков (например: от А1 до С1).
  3. Депандирование другого под (локального) диапазона в пределах диапазона testCase для заголовков (в моем случае: от D1 до E14).
  4. Заполните два поддиапазона значениями тестового примера (заголовки и шаги).
  5. Повторите, отложив следующий диапазон таблиц (от A14 до E28 в моем случае) с теми же локальными диапазонами (шаги 2-3), и заполните их, и так далее...

Исходным значением является словарь, который представляет шаги тестового примера (ключ = ожидаемый, а значение = фактический).

Вот код, который я использую:

public class TestCase
{
    public Dictionary<string, string> steps;
}

Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();
Workbooks workBooks = excelApp.Workbooks;
Workbook workbook = workBooks.Add(XlWBATemplate.xlWBATWorksheet);
Worksheet worksheet = (Worksheet)workbook.Worksheets[1];
excelApp.Visible = true;

foreach (TestCase testCase in TestCaseList.Items.GetList())
{
    Range worksheetRange = GetRangeForTestCase(worksheet);
    //The step above is equivalent to:
    //    Range worksheetRange = worksheet.get_Range("A1", "E14");
    //for the first foreach iteration.

    Range stepsRange = worksheetRange.get_Range("D1", "E14");
    //This is a local range within the worksheetRange, not the worksheet,
    //so it is always have to be between D1 to E14 for a 14th steps test case.
    //Anyway, it should work at least for the 1st iteration.

    //for test evaluation only. All cells between D1 to E14 are filled with "ccc"
    test.Value = "ccc";

    //This list of pairs which are converted to Array[,] is about to be converted to a two dimensional array
    list = new List<object>();
    foreach (KeyValuePair<string, string> item in testCase.Steps)
    {
        //Here I build the inside Array[,]
        object[] tempArgs = {item.Key, item.Value};
        list.Add(tempArgs);
    }
    object[] args = { Type.Missing, list.ToArray() };

    test.GetType().InvokeMember("Value", System.Reflection.BindingFlags.SetProperty, null, test, args);

    //Now, all the "ccc" within the Excel worksheet are disapeared, so the Range is correct, but the value of args[] are not set!!
}

Фактический результат выполнения этого кода состоит в том, что диапазон определен (вероятно, правильно), но его значения установлены в нуль, хотя - я могу видеть правильные значения в массиве args во время выполнения. Я также попытался установить более широкий диапазон и заполнить его range.Value = "Pake value" и увидел, что после выполнения моего кода, правильный диапазон шагов становится пустым! Итак, диапазон правильный, массив заполнен моими значениями, метод InvokeMember корректно вызывается:) Но все значения имеют значение null..

Помогите...

2 ответа

Решение

Одна ячейка или массив 1dim могут быть установлены одним из следующих способов:

Range range = SetRange();//Let's say range is set between A1 to D1
object[] args = {1, 2, 3, 4 }; 

//Directly
range.Value = args;

//By Reflection
range.GetType().InvokeMember("Value", System.Reflection.BindingFlags.SetProperty, null, range, args);

Массив 2dim не может быть установлен напрямую, поэтому необходимо использовать поток отражения, чтобы установить матрицу значений. Эта матрица должна быть построена перед множеством, как это:

Range range = SetRange();//Let's say range is set between A1 to C5
int rows = 5;
int columns = 3;
object[,] data = new object[rows, columns];
for (int i = 0; i < rows; i++)
{
    for (int j = 0; j < columns; j++)
    {
        //Here I build the inside Array[,]
        string uniqueValue = (i + j).ToString();
        data[i, j] = "Insert your string value here, e.g: " + uniqueValue;
    }
}
object[] args = { data };
range.GetType().InvokeMember("Value", System.Reflection.BindingFlags.SetProperty, null, range, args);

Что касается вашей проблемы, весь диапазон установлен в нуль, я думаю, что это из-за неправильных аргументов.

Действительно, почему Type.Missing в списке аргументов?

Следовательно, это должен быть шаг в правильном направлении:

object[] args = { list.ToArray() };
test.GetType().InvokeMember("Value", System.Reflection.BindingFlags.SetProperty, null, test, args);

Более того, list.ToArray будет генерировать только массив массивов, а не матрицу, поэтому вы должны строить свою матрицу иначе, например:

object[,] data = new object[14, 2];
int row = 0;
foreach (KeyValuePair<string, string> item in testCase.Steps)
{
    //Here I build the inside Array[,]
    data[row, 0] = item.Key;
    data[row, 1] = item.Value;
    ++row;
}
object[] args = { data };

И каков смысл использования InvokeMember вместо более простого:

test.Value = data;

?

Надеюсь это поможет...

Другие вопросы по тегам