openxml - вставка строки, перемещение других

Я использую openxml для создания отчета excel. openxml работает с файлом шаблона excel, используя именованные диапазоны.

Клиенту требуется итоговая строка в конце списка строк. Звучит как разумная просьба!!

Однако таблица данных, которую я возвращаю из базы данных, может содержать любое количество строк. Используя строки шаблона и «InsertBeforeSelf», моя строка итогов переопределяется.

Мой вопрос: используя openxml, как я могу вставлять строки в электронную таблицу, в результате чего строка итогов перемещается вниз каждый раз, когда вставляется строка?

С уважением ...


person bmoyno    schedule 24.06.2010    source источник


Ответы (3)


Предполагая, что вы используете SDK 2.0, я сделал нечто подобное, используя эту функцию:

private static Row CreateRow(Row refRow, SheetData sheetData)
    {
        uint rowIndex = refRow.RowIndex.Value;
        uint newRowIndex;
        var newRow = (Row)refRow.Clone();

        /*IEnumerable<Row> rows = sheetData.Descendants<Row>().Where(r => r.RowIndex.Value >= rowIndex);
        foreach (Row row in rows)
        {
            newRowIndex = System.Convert.ToUInt32(row.RowIndex.Value + 1);

            foreach (Cell cell in row.Elements<Cell>())
            {
                string cellReference = cell.CellReference.Value;
                cell.CellReference = new StringValue(cellReference.Replace(row.RowIndex.Value.ToString(), newRowIndex.ToString()));
            }

            row.RowIndex = new UInt32Value(newRowIndex);
        }*/

        sheetData.InsertBefore(newRow, refRow);
        return newRow;
    }

Я не уверен, как вы делали это с InsertBeforeSelf раньше, так что, возможно, это не так уж много улучшений, но это сработало для меня. Я подумал, что вы могли бы просто использовать свою итоговую строку в качестве справочной строки. (Закомментированная часть предназначена для тех случаев, когда после ссылочной строки у вас есть строки, которые вы хотите сохранить. Я внес некоторые изменения, но в основном они взяты из этой темы: http://social.msdn.microsoft.com)

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

person M_R_H    schedule 14.07.2010
comment
Имейте в виду, что ячейки слияния хранятся в отдельном объекте. Если вы хотите сохранить правильный формат слияния, вам следует обновить их ссылки. Пожалуйста, проверьте stackoverflow.com/a/11455088/1099945 - person gyosifov; 12.06.2014

[Может ли кто-нибудь с большим количеством баллов поместить этот текст в качестве комментария к ответу M_R_H.]

Решение, которое дал M_R_H, помогло мне, но вносит в проблему новую ошибку. Если вы используете данный метод CreateRow как есть, если какая-либо из перемещаемых/повторно ссылающихся строк содержит формулы, CalcChain.xml (в пакете) будет нарушен. Я добавил следующий код в предлагаемое решение CreateRow. Это все еще не решает проблему, потому что я думаю, что этот код исправляет только текущую ссылку на строку:

if (cell.CellFormula != null) {
     string cellFormula = cell.CellFormula.Text;
     cell.CellFormula = new CellFormula(cellFormula.Replace(row.RowIndex.Value.ToString(), newRowIndex.ToString()));
}

Как правильно исправить/обновить CalcChain.xml?

PS: SheetData можно получить с вашего листа как:

worksheet.GetFirstChild<SheetData>();
person Omar    schedule 12.01.2011

Вы должны зациклить все строки и ячейки под вставленной строкой, изменить ее индекс строки и ссылку на ячейку. Я предполагаю, что OpenXml не настолько умен, чтобы помочь вам автоматически изменить индекс.

static void InsertRow(string sheetName, WorkbookPart wbPart, uint rowIndex)
    {
        Sheet sheet = wbPart.Workbook.Descendants<Sheet>().Where((s) => s.Name == sheetName).FirstOrDefault();

        if (sheet != null)
        {
            Worksheet ws = ((WorksheetPart)(wbPart.GetPartById(sheet.Id))).Worksheet;
            SheetData sheetData = ws.WorksheetPart.Worksheet.GetFirstChild<SheetData>();
            Row refRow = GetRow(sheetData, rowIndex);
            ++rowIndex;

            Cell cell1 = new Cell() { CellReference = "A" + rowIndex };
            CellValue cellValue1 = new CellValue();
            cellValue1.Text = "";
            cell1.Append(cellValue1);
            Row newRow = new Row()
            {
                RowIndex = rowIndex
            };
            newRow.Append(cell1);
            for (int i = (int)rowIndex; i <= sheetData.Elements<Row>().Count(); i++)
            {
                var row = sheetData.Elements<Row>().Where(r => r.RowIndex.Value == i).FirstOrDefault();
                row.RowIndex++;
                foreach (Cell c in row.Elements<Cell>())
                {
                    string refer = c.CellReference.Value;
                    int num = Convert.ToInt32(Regex.Replace(refer, @"[^\d]*", ""));
                    num++;
                    string letters = Regex.Replace(refer, @"[^A-Z]*", "");
                    c.CellReference.Value = letters + num;
                }
            }
            sheetData.InsertAfter(newRow, refRow);
            //ws.Save();
        }
    }

    static Row GetRow(SheetData wsData, UInt32 rowIndex)
    {
        var row = wsData.Elements<Row>().
        Where(r => r.RowIndex.Value == rowIndex).FirstOrDefault();
        if (row == null)
        {
            row = new Row();
            row.RowIndex = rowIndex;
            wsData.Append(row);
        }
        return row;
    }

Вышеупомянутое решение получено из: in-exisiting-template-in-open-xml?forum=oxmlsdk" rel="nofollow noreferrer">Как вставить строку в существующий шаблон в открытый xml. Существует четкое объяснение может помочь вам много.

person 劉鎮瑲    schedule 17.01.2019