Как установить массив C# в значение ячейки с помощью Excel Interop, чтобы ячейка «разливалась»

Я использую Microsoft.Office.Interop.Excel, чтобы открыть рабочую книгу. Затем я нахожу нужный мне рабочий лист и нахожу на нем именованную ячейку. Я хочу иметь возможность устанавливать значение ячейки в массив, чтобы эти значения «разливались» (термин Excel).

Если я установлю значение ячейки в Excel вручную вот так

= {1;2;3}

Я получу разлив, где в первой ячейке будет 1, затем в той, что ниже, будет 2, а затем 3 ниже. То же самое для

= {"foo";"bar";"fizz"}

Мне бы хотелось иметь функцию на С#, которая могла бы принимать динамический массив и записывать его в ячейку. Я мог бы использовать StringBuilder, чтобы объединить все значения, а затем установить формулу ячейки. Но если динамический массив представляет собой строки, мне придется беспокоиться о кавычках.

Есть ли более простой способ добиться желаемого поведения? Вот что у меня есть на данный момент. Этот метод предназначен для класса, который обрабатывает открытие файла Excel. Это также часть плагина AutoCAD, который является объектом транзакции, но это не особо важно.


public void testMethod3(Transaction tr)//AutoCAD object
{
    var pages = Workbook.Worksheets.Cast<Worksheet>()
        .Where(sheet => sheet.Name.Contains("Export"))
        .ToList();

    if (pages.Count != 1) return;

    if (!Save)
    {
        pages.ForEach(p =>
        {
            p.Columns.ClearFormats();
            p.Rows.ClearFormats();
        });
    }

    dynamic range = pages[0]?.Names?.Item("LoopRoom")?.RefersToRange?.Cells;

    List<MyObject> myObjects = //data objects with string property RoomName

    object[,] data = new object[myObjects.Count+1,1];

    for (int i = 0; i < loops.Count; i++)
    {
        data[i, 0] = myObjects[i].RoomName;
    }

    


    range.Value2 = data;

}

Редактировать 0:

В ответ на @rotabor

Мне пришлось немного изменить код, но это сработало. Хотя в Excel даты отображались как «#####», пока я не щелкнул ячейку и не вышел из нее. Вот модифицированный код.

public void testMethod4(string path)
{
    Microsoft.Office.Interop.Excel.Application oXL; Microsoft.Office.Interop.Excel.Workbook oWB; Microsoft.Office.Interop.Excel.Worksheet oSheet;
    try
    {
        oXL = new Microsoft.Office.Interop.Excel.Application
        {
            Visible = false
        };
        //oXL.Visible = true;
        oWB = oXL.Workbooks.Open(path);
        oSheet = (Microsoft.Office.Interop.Excel.Worksheet)oWB.ActiveSheet;
        oSheet.Range["A1:B2"].Value = new object[,] { { 1, 2 }, { 3, null } };
        var itm = new object[] { 1, "Hello, World!", DateTime.Now };
        oSheet.Range[oSheet.Cells[4, 1], oSheet.Cells[4, itm.Length]].Value = itm;

        dynamic range = oSheet.Names.Item("SORange").RefersToRange.Cells;
        itm = new object[] { 2, "Hello, StackOverflow!", DateTime.Now };
        range.Value = itm;

        oWB.Save();
        oWB.Close(false);
        oXL.Quit();
    }
    catch (Exception theException)
    {
        String errorMessage;
        errorMessage = "Error: ";
        errorMessage = String.Concat(errorMessage, theException.Message);
        errorMessage = String.Concat(errorMessage, " Line: ");
        errorMessage = String.Concat(errorMessage, theException.Source);
        
    }
}

Проблема в том, что «диапазон», который я хочу использовать, представляет собой одну ячейку, и внутри этой ячейки я хочу поместить массив, который будет распространяться на другие ячейки ниже.

🤔 А знаете ли вы, что...
C# позволяет создавать приложения для разных платформ, включая Windows, Linux и macOS, с использованием .NET Core и .NET 5+.


1
50
1

Ответ:

Решено

Прежде всего, ниже приведен рабочий код:

using System;
using Excel = Microsoft.Office.Interop.Excel;
using System.Windows.Forms; 
//csc /r:"C:\Program Files\Microsoft Office\root\Office16\ADDINS\PowerPivot Excel Add-in\Microsoft.Office.Interop.Excel.dll" excel.cs
namespace TestConsoleApp {
    class Program {
       static void Main() {
            Excel.Application oXL; Excel.Workbook oWB; Excel.Worksheet oSheet;
            try {
                oXL = new Excel.Application();
                oXL.Visible = true;
                oWB = oXL.Workbooks.Open("C:\\Users\\ashatikhin\\Documents\\My Projects\\Stackoverflow\\Book333.xlsx");
                oSheet = (Excel.Worksheet)oWB.ActiveSheet;
                oSheet.Range["A1:B2"].Value = new object[,] { { 1, 2 }, { 3, null } };
                var itm = new object[] { 1, "Hello, World!", DateTime.Now };
                oSheet.get_Range(oSheet.Cells[4, 1], oSheet.Cells[4, itm.Length]).Value = itm;
                dynamic range = oWB.Names.Item("SORange").RefersToRange.Cells;
                itm = new object[] { 2, "Hello, StackOverflow!", DateTime.Now };
                range.Value = itm;
                range = oWB.Names.Item("StringsOnly").RefersToRange.Cells;
                var sqitm = new object[,] { { "One", "Two" }, { "Three", "Four" } };
                range.Value = sqitm;
                var sa = new string[] { "June", "July", "August" };
                range = oSheet.Range["A8"];
                range.Formula2 = " = {\"" + string.Join("\";\"", sa) + "\"}";
                oWB.Save();
                oWB.Close(false);
                oXL.Quit();
            }
            catch( Exception theException ) 
            {
                String errorMessage;
                errorMessage = "Error: ";
                errorMessage = String.Concat( errorMessage, theException.Message );
                errorMessage = String.Concat( errorMessage, " Line: " );
                errorMessage = String.Concat( errorMessage, theException.Source );
                MessageBox.Show( errorMessage, "Error" );
            }
        }
    }
}

Вам нужно использовать тип dynamic и свойство Formula2, чтобы задать формулу с помощью динамических массивов.

Можете ли вы протестировать это и уточнить свои ожидания и что не так?

П. С. Это может быть самый простой способ для вас:

itm = new object[] { 2, "Hello, StackOverflow!", DateTime.Now };
oSheet.Range["A12"].Resize[1, itm.Length].Value = itm;