Freigeben über


Anleitung: Zusammenführen zweier angrenzender Zellen in einem Kalkulationstabellendokument

Letzte Änderung: Dienstag, 30. November 2010

Gilt für: Excel 2010 | Office 2010 | PowerPoint 2010 | Word 2010

Inhalt dieses Artikels
Abrufen eines SpreadsheetDocument-Objekts
Grundlegende Struktur eines SpreadsheetML-Dokuments
Funktionsweise des Beispielcodes
Beispielcode

In diesem Thema wird erklärt, wie Sie mithilfe der Klassen im Open XML SDK 2.0 für Microsoft Office programmgesteuert zwei benachbarte Zellen in einem Tabellenkalkulationsdokument verbinden können.

Die folgenden Assemblydirektiven sind zum Kompilieren des Codes in diesem Thema erforderlich.

using System;
using System.Collections.Generic;
using System.Linq;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using System.Text.RegularExpressions;
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports DocumentFormat.OpenXml
Imports DocumentFormat.OpenXml.Packaging
Imports DocumentFormat.OpenXml.Spreadsheet
Imports System.Text.RegularExpressions

Abrufen eines SpreadsheetDocument-Objekts

Im Open XML SDK stellt die SpreadsheetDocument-Klasse ein Excel-Dokumentpaket dar. Zum Öffnen und Bearbeiten eines Excel-Dokuments müssen Sie anhand des Dokuments eine Instanz der SpreadsheetDocument-Klasse erstellen. Nachdem Sie die Instanz anhand des Dokuments erstellt haben, können Sie Zugriff auf den Hauptarbeitsmappenteil erhalten, der die Arbeitsblätter enthält. Der Text im Dokument wird im Paket mithilfe des SpreadsheetML-Markups als XML dargestellt.

Zum Erstellen der Klasseninstanz anhand des Dokuments rufen Sie eine der Open()-Methodenüberladungen auf, von denen mehrere mit einer jeweils anderen Signatur bereitgestellt werden. Der Beispielcode in diesem Thema arbeitet mit der Open(String, Boolean)-Methode mit einer Signatur, die zwei Parameter erfordert. Der erste Parameter arbeitet mit einer vollständigen Pfadzeichenfolge, die das Dokument darstellt, das Sie öffnen möchten. Der zweite Parameter ist entweder true oder false und bestimmt, ob die Datei zum Bearbeiten geöffnet werden soll. Ist dieser Parameter auf false festgelegt, werden Ihre Änderungen am Dokument nicht gespeichert.

Der Code zum Aufrufen der Open-Methode wird in der folgenden using-Anweisung gezeigt.

// Open the document for editing.
using (SpreadsheetDocument document = SpreadsheetDocument.Open(docName, true)) 
{
    // Insert other code here.
}
' Open the document for editing.
Using document As SpreadsheetDocument = SpreadsheetDocument.Open(docName, True)
    ' Insert other code here.
End Using

Die using-Anweisung ist eine empfohlene Alternative zur herkömmlichen Reihenfolge ".Open, .Save, .Close". Sie stellt sicher, dass die Dispose-Methode (vom Open XML SDK verwendete interne Methode zum Bereinigen von Ressourcen) bei Erreichen der schließenden Klammer automatisch aufgerufen wird. Der auf die using-Anweisung folgende Block richtet einen Bereich für das Objekt ein, das in der using-Anweisung erstellt oder benannt wird, in diesem Fall document.

Grundlegende Struktur eines SpreadsheetML-Dokuments

Die grundlegende Dokumentstruktur eines SpreadsheetML-Dokuments besteht aus den Elementen Sheets und Sheet, welche die Arbeitsblätter im Workbook-Objekt referenzieren. Für jedes Worksheet-Objekt wird eine XML-Datei erstellt. Beispiel: Der SpreadsheetML-Code für eine Arbeitsmappe mit zwei Arbeitsblättern mit den Namen "MySheet1" und "MySheet2" befindet sich in der Datei Workbook.xml und sieht wie im folgenden Codebeispiel aus.

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> 
<workbook xmlns=https://schemas.openxmlformats.org/spreadsheetml/2006/main xmlns:r="https://schemas.openxmlformats.org/officeDocument/2006/relationships">
    <sheets>
        <sheet name="MySheet1" sheetId="1" r:id="rId1" /> 
        <sheet name="MySheet2" sheetId="2" r:id="rId2" /> 
    </sheets>
</workbook>

Die XML-Dateien der Arbeitsblätter enthalten ein oder mehrere Elemente auf Blockebene, z. B. SheetData. sheetData stellt die Zellentabelle dar und enthält ein oder mehrere Row-Elemente. Ein row-Objekt enthält ein oder mehrere Cell-Elemente. Jede Zelle enthält ein CellValue-Element, das den Wert der Zelle darstellt. Beispiel: Der SpreadsheetML-Code des ersten Arbeitsblatts in einer Arbeitsmappe, das nur den Wert 100 in Zelle A1 enthält, ist in der Datei Sheet1.xml enthalten und sieht wie im folgenden Codebeispiel aus.

<?xml version="1.0" encoding="UTF-8" ?> 
<worksheet xmlns="https://schemas.openxmlformats.org/spreadsheetml/2006/main">
    <sheetData>
        <row r="1">
            <c r="A1">
                <v>100</v> 
            </c>
        </row>
    </sheetData>
</worksheet>

Mithilfe des Open XML SDK 2.0 können Sie eine Dokumentstruktur und Inhalte erstellen, indem Sie stark typisierte Klassen verwenden, die SpreadsheetML-Elementen entsprechen. Diese Klassen sind im DocumentFormat.OpenXML.Spreadsheet-Namespace enthalten. Die folgende Tabelle enthält die Namen der Klassen, die den Elementen workbook, sheets, sheet, worksheet und sheetData entsprechen.

SpreadsheetML-Element

Open XML SDK 2.0-Klasse

Beschreibung

workbook

DocumentFormat.OpenXML.Spreadsheet.Workbook

Das Stammelement des Hauptdokumentteils.

sheets

DocumentFormat. OpenXML.Spreadsheet.Sheets

Der Container für die Strukturen auf Blockebene, wie z. B. "sheet", "fileVersion" und andere Elemente, die in der Spezifikation ISO/IEC 29500 angegeben sind.

sheet

DocumentFormat.OpenXML.Spreadsheet.Sheet

Ein Blatt, das auf eine Blattdefinitionsdatei zeigt.

worksheet

DocumentFormat.OpenXML.Spreadsheet.Worksheet

Eine Blattdefinitionsdatei, welche die Blattdaten enthält.

sheetData

DocumentFormat.OpenXML.Spreadsheet.SheetData

Die Zellentabelle, die mithilfe von Zeilen gruppiert wird.

row

DocumentFormat.OpenXml.Spreadsheet.Row

Eine Zeile in der Zellentabelle.

c

DocumentFormat.OpenXml.Spreadsheet.Cell

Eine Zelle in einer Zeile.

v

DocumentFormat.OpenXml.Spreadsheet.CellValue

Der Wert einer Zelle.

Funktionsweise des Beispielcodes

Nach dem Öffnen der Tabellenkalkulationsdatei für die Bearbeitung wird im Code überprüft, ob die angegebenen Zellen vorhanden sind. Falls nicht, werden sie mit einem Aufruf der CreateSpreadsheetCellIfNotExist-Methode erstellt und an das entsprechende Row-Objekt angefügt.

// Given a Worksheet and a cell name, verifies that the specified cell exists.
// If it does not exist, creates a new cell. 
private static void CreateSpreadsheetCellIfNotExist(Worksheet worksheet, string cellName)
{
    string columnName = GetColumnName(cellName);
    uint rowIndex = GetRowIndex(cellName);

    IEnumerable<Row> rows = worksheet.Descendants<Row>().Where(r => r.RowIndex.Value == rowIndex);

    // If the Worksheet does not contain the specified row, create the specified row.
    // Create the specified cell in that row, and insert the row into the Worksheet.
    if (rows.Count() == 0)
    {
        Row row = new Row() { RowIndex = new UInt32Value(rowIndex) };
        Cell cell = new Cell() { CellReference = new StringValue(cellName) };
        row.Append(cell);
        worksheet.Descendants<SheetData>().First().Append(row);
        worksheet.Save();
    }
    else
    {
        Row row = rows.First();

        IEnumerable<Cell> cells = row.Elements<Cell>().Where(c => c.CellReference.Value == cellName);

        // If the row does not contain the specified cell, create the specified cell.
        if (cells.Count() == 0)
        {
            Cell cell = new Cell() { CellReference = new StringValue(cellName) };
            row.Append(cell);
            worksheet.Save();
        }
    }
}
' Given a Worksheet and a cell name, verifies that the specified cell exists.
' If it does not exist, creates a new cell.
Private Sub CreateSpreadsheetCellIfNotExist(ByVal worksheet As Worksheet, ByVal cellName As String)
    Dim columnName As String = GetColumnName(cellName)
    Dim rowIndex As UInteger = GetRowIndex(cellName)

    Dim rows As IEnumerable(Of Row) = worksheet.Descendants(Of Row)().Where(Function(r) r.RowIndex.Value = rowIndex.ToString())

    ' If the worksheet does not contain the specified row, create the specified row.
    ' Create the specified cell in that row, and insert the row into the worksheet.
    If (rows.Count = 0) Then
        Dim row As Row = New Row()
        row.RowIndex = New UInt32Value(rowIndex)

        Dim cell As Cell = New Cell()
        cell.CellReference = New StringValue(cellName)

        row.Append(cell)
        worksheet.Descendants(Of SheetData)().First().Append(row)
        worksheet.Save()
    Else
        Dim row As Row = rows.First()
        Dim cells As IEnumerable(Of Cell) = row.Elements(Of Cell)().Where(Function(c) c.CellReference.Value = cellName)

        ' If the row does not contain the specified cell, create the specified cell.
        If (cells.Count = 0) Then
            Dim cell As Cell = New Cell
            cell.CellReference = New StringValue(cellName)

            row.Append(cell)
            worksheet.Save()
        End If
    End If
End Sub

Zum Abrufen eines Spaltennamens wird im Code ein neuer regulärer Ausdruck erstellt, der den Spaltennamenteil des Zellennamens abgleicht. Dieser reguläre Ausdruck gleicht beliebige Kombinationen von Groß- bzw. Kleinbuchstaben ab. Weitere Informationen zu regulären Ausdrücken finden Sie unter Sprachelemente für reguläre Ausdrücke. Der Code ruft den Spaltennamen durch einen Aufruf der Regex.Match-Methode ab.

// Given a cell name, parses the specified cell to get the column name.
private static string GetColumnName(string cellName)
{
    // Create a regular expression to match the column name portion of the cell name.
    Regex regex = new Regex("[A-Za-z]+");
    Match match = regex.Match(cellName);

    return match.Value;
}
' Given a cell name, parses the specified cell to get the column name.
Private Function GetColumnName(ByVal cellName As String) As String
    ' Create a regular expression to match the column name portion of the cell name.
    Dim regex As Regex = New Regex("[A-Za-z]+")
    Dim match As Match = regex.Match(cellName)
    Return match.Value
End Function

Zum Abrufen des Zeilenindexes wird im Code ein neuer regulärer Ausdruck erstellt, der den Zeilenindexteil des Zellennamens abgleicht. Dieser reguläre Ausdruck gleicht beliebige Kombinationen von Dezimalziffern ab. Im folgenden Code wird ein regulärer Ausdruck zum Abgleichen des Zeilenindexteils des Zellennamens bestehend aus Dezimalziffern erstellt.

// Given a cell name, parses the specified cell to get the row index.
private static uint GetRowIndex(string cellName)
{
    // Create a regular expression to match the row index portion the cell name.
    Regex regex = new Regex(@"\d+");
    Match match = regex.Match(cellName);

    return uint.Parse(match.Value);
}
' Given a cell name, parses the specified cell to get the row index.
Private Function GetRowIndex(ByVal cellName As String) As UInteger
    ' Create a regular expression to match the row index portion the cell name.
    Dim regex As Regex = New Regex("\d+")
    Dim match As Match = regex.Match(cellName)
    Return UInteger.Parse(match.Value)
End Function

Beispielcode

Im folgenden Code werden zwei benachbarte Zellen in einem SpreadsheetDocument-Dokumentpaket verbunden. Beim Verbinden zweier Zellen bleibt nur der Inhalt einer Zelle erhalten. Bei von links nach rechts gelesenen und geschriebenen Sprachen bleibt der Inhalt in der linken oberen Zelle erhalten. Bei von rechts nach links gelesenen und geschriebenen Sprachen bleibt der Inhalt in der rechten oberen Zelle erhalten. Sie können die MergeTwoCells-Methode in einem Programm mit dem folgenden Beispielcode aufrufen, in dem die Zellen B2 und C2 in einem Blatt namens "Jane" in einer Datei namens "Sheet9.xlsx" verbunden werden.

string docName = @"C:\Users\Public\Documents\Sheet9.xlsx";
string sheetName = "Jane";
string cell1Name = "B2";
string cell2Name = "C2";
MergeTwoCells(docName, sheetName, cell1Name, cell2Name);
Dim docName As String = "C:\Users\Public\Documents\Sheet9.xlsx"
Dim sheetName As String = "Jane"
Dim cell1Name As String = "B2"
Dim cell2Name As String = "C2"
MergeTwoCells(docName, sheetName, cell1Name, cell2Name)

Nachstehend ist der vollständige Beispielcode in C# und Visual Basic aufgeführt.

// Given a document name, a worksheet name, and the names of two adjacent cells, merges the two cells.
// When two cells are merged, only the content from one cell is preserved:
// the upper-left cell for left-to-right languages or the upper-right cell for right-to-left languages.
private static void MergeTwoCells(string docName, string sheetName, string cell1Name, string cell2Name)
{
    // Open the document for editing.
    using (SpreadsheetDocument document = SpreadsheetDocument.Open(docName, true))
    {
        Worksheet worksheet = GetWorksheet(document, sheetName);
        if (worksheet == null || string.IsNullOrEmpty(cell1Name) || string.IsNullOrEmpty(cell2Name))
        {
            return;
        }

        // Verify if the specified cells exist, and if they do not exist, create them.
        CreateSpreadsheetCellIfNotExist(worksheet, cell1Name);
        CreateSpreadsheetCellIfNotExist(worksheet, cell2Name);

        MergeCells mergeCells;
        if (worksheet.Elements<MergeCells>().Count() > 0)
        {
            mergeCells = worksheet.Elements<MergeCells>().First();
        }
        else
        {
            mergeCells = new MergeCells();

            // Insert a MergeCells object into the specified position.
            if (worksheet.Elements<CustomSheetView>().Count() > 0)
            {
                worksheet.InsertAfter(mergeCells, worksheet.Elements<CustomSheetView>().First());
            }
            else if (worksheet.Elements<DataConsolidate>().Count() > 0)
            {
                worksheet.InsertAfter(mergeCells, worksheet.Elements<DataConsolidate>().First());
            }
            else if (worksheet.Elements<SortState>().Count() > 0)
            {
                worksheet.InsertAfter(mergeCells, worksheet.Elements<SortState>().First());
            }
            else if (worksheet.Elements<AutoFilter>().Count() > 0)
            {
                worksheet.InsertAfter(mergeCells, worksheet.Elements<AutoFilter>().First());
            }
            else if (worksheet.Elements<Scenarios>().Count() > 0)
            {
                worksheet.InsertAfter(mergeCells, worksheet.Elements<Scenarios>().First());
            }
            else if (worksheet.Elements<ProtectedRanges>().Count() > 0)
            {
                worksheet.InsertAfter(mergeCells, worksheet.Elements<ProtectedRanges>().First());
            }
            else if (worksheet.Elements<SheetProtection>().Count() > 0)
            {
                worksheet.InsertAfter(mergeCells, worksheet.Elements<SheetProtection>().First());
            }
            else if (worksheet.Elements<SheetCalculationProperties>().Count() > 0)
            {
                worksheet.InsertAfter(mergeCells, worksheet.Elements<SheetCalculationProperties>().First());
            }
            else
            {
                worksheet.InsertAfter(mergeCells, worksheet.Elements<SheetData>().First());
            }
        }

        // Create the merged cell and append it to the MergeCells collection.
        MergeCell mergeCell = new MergeCell() { Reference = new StringValue(cell1Name + ":" + cell2Name) };
        mergeCells.Append(mergeCell);

        worksheet.Save();
    }
}
// Given a Worksheet and a cell name, verifies that the specified cell exists.
// If it does not exist, creates a new cell. 
private static void CreateSpreadsheetCellIfNotExist(Worksheet worksheet, string cellName)
{
    string columnName = GetColumnName(cellName);
    uint rowIndex = GetRowIndex(cellName);

    IEnumerable<Row> rows = worksheet.Descendants<Row>().Where(r => r.RowIndex.Value == rowIndex);

    // If the Worksheet does not contain the specified row, create the specified row.
    // Create the specified cell in that row, and insert the row into the Worksheet.
    if (rows.Count() == 0)
    {
        Row row = new Row() { RowIndex = new UInt32Value(rowIndex) };
        Cell cell = new Cell() { CellReference = new StringValue(cellName) };
        row.Append(cell);
        worksheet.Descendants<SheetData>().First().Append(row);
        worksheet.Save();
    }
    else
    {
        Row row = rows.First();

        IEnumerable<Cell> cells = row.Elements<Cell>().Where(c => c.CellReference.Value == cellName);

        // If the row does not contain the specified cell, create the specified cell.
        if (cells.Count() == 0)
        {
            Cell cell = new Cell() { CellReference = new StringValue(cellName) };
            row.Append(cell);
            worksheet.Save();
        }
    }
}

// Given a SpreadsheetDocument and a worksheet name, get the specified worksheet.
private static Worksheet GetWorksheet(SpreadsheetDocument document, string worksheetName)
{
    IEnumerable<Sheet> sheets = document.WorkbookPart.Workbook.Descendants<Sheet>().Where(s => s.Name == worksheetName);
    WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart.GetPartById(sheets.First().Id)
    if (sheets.Count() == 0)
        return null;
    else
        return worksheetPart.Worksheet;
}

// Given a cell name, parses the specified cell to get the column name.
private static string GetColumnName(string cellName)
{
    // Create a regular expression to match the column name portion of the cell name.
    Regex regex = new Regex("[A-Za-z]+");
    Match match = regex.Match(cellName);

    return match.Value;
}
// Given a cell name, parses the specified cell to get the row index.
private static uint GetRowIndex(string cellName)
{
    // Create a regular expression to match the row index portion the cell name.
    Regex regex = new Regex(@"\d+");
    Match match = regex.Match(cellName);

    return uint.Parse(match.Value);
}
' Given a document name, a worksheet name, and the names of two adjacent cells, merges the two cells.
' When two cells are merged, only the content from one cell is preserved:
' the upper-left cell for left-to-right languages or the upper-right cell for right-to-left languages.
Private Sub MergeTwoCells(ByVal docName As String, ByVal sheetName As String, ByVal cell1Name As String, ByVal cell2Name As String)
' Open the document for editing.
Dim document As SpreadsheetDocument = SpreadsheetDocument.Open(docName, True)

Using (document)
Dim worksheet As Worksheet = GetWorksheet(document, sheetName)
If ((worksheet Is Nothing) OrElse (String.IsNullOrEmpty(cell1Name) OrElse String.IsNullOrEmpty(cell2Name))) Then
Return
End If

' Verify if the specified cells exist, and if they do not exist, create them.
CreateSpreadsheetCellIfNotExist(worksheet, cell1Name)
CreateSpreadsheetCellIfNotExist(worksheet, cell2Name)

Dim mergeCells As MergeCells
If (worksheet.Elements(Of MergeCells)().Count() > 0) Then
mergeCells = worksheet.Elements(Of MergeCells).First()
Else
mergeCells = New MergeCells()

' Insert a MergeCells object into the specified position.
If (worksheet.Elements(Of CustomSheetView)().Count() > 0) Then
worksheet.InsertAfter(mergeCells, worksheet.Elements(Of CustomSheetView)().First())
ElseIf (worksheet.Elements(Of DataConsolidate)().Count() > 0) Then
worksheet.InsertAfter(mergeCells, worksheet.Elements(Of DataConsolidate)().First())
ElseIf (worksheet.Elements(Of SortState)().Count() > 0) Then
worksheet.InsertAfter(mergeCells, worksheet.Elements(Of SortState)().First())
ElseIf (worksheet.Elements(Of AutoFilter)().Count() > 0) Then
worksheet.InsertAfter(mergeCells, worksheet.Elements(Of AutoFilter)().First())
ElseIf (worksheet.Elements(Of Scenarios)().Count() > 0) Then
worksheet.InsertAfter(mergeCells, worksheet.Elements(Of Scenarios)().First())
ElseIf (worksheet.Elements(Of ProtectedRanges)().Count() > 0) Then
worksheet.InsertAfter(mergeCells, worksheet.Elements(Of ProtectedRanges)().First())
ElseIf (worksheet.Elements(Of SheetProtection)().Count() > 0) Then
worksheet.InsertAfter(mergeCells, worksheet.Elements(Of SheetProtection)().First())
ElseIf (worksheet.Elements(Of SheetCalculationProperties)().Count() > 0) Then
worksheet.InsertAfter(mergeCells, worksheet.Elements(Of SheetCalculationProperties)().First())
Else
worksheet.InsertAfter(mergeCells, worksheet.Elements(Of SheetData)().First())
End If
End If

' Create the merged cell and append it to the MergeCells collection.
Dim mergeCell As MergeCell = New MergeCell()
mergeCell.Reference = New StringValue((cell1Name + (":" + cell2Name)))
mergeCells.Append(mergeCell)

worksheet.Save()
End Using
End Sub

' Given a SpreadsheetDocument and a worksheet name, get the specified worksheet.
Private Function GetWorksheet(ByVal document As SpreadsheetDocument, ByVal worksheetName As String) As Worksheet
Dim sheets As IEnumerable(Of Sheet) = document.WorkbookPart.Workbook.Descendants(Of Sheet)().Where(Function(s) s.Name = worksheetName)
If (sheets.Count = 0) Then
' The specified worksheet does not exist.
Return Nothing
End If
Dim worksheetPart As WorksheetPart = CType(document.WorkbookPart.GetPartById(sheets.First.Id), WorksheetPart)

Return worksheetPart.Worksheet
End Function

' Given a Worksheet and a cell name, verifies that the specified cell exists.
' If it does not exist, creates a new cell.
Private Sub CreateSpreadsheetCellIfNotExist(ByVal worksheet As Worksheet, ByVal cellName As String)
Dim columnName As String = GetColumnName(cellName)
Dim rowIndex As UInteger = GetRowIndex(cellName)

Dim rows As IEnumerable(Of Row) = worksheet.Descendants(Of Row)().Where(Function(r) r.RowIndex.Value = rowIndex.ToString())

' If the worksheet does not contain the specified row, create the specified row.
' Create the specified cell in that row, and insert the row into the worksheet.
If (rows.Count = 0) Then
Dim row As Row = New Row()
row.RowIndex = New UInt32Value(rowIndex)

Dim cell As Cell = New Cell()
cell.CellReference = New StringValue(cellName)

row.Append(cell)
worksheet.Descendants(Of SheetData)().First().Append(row)
worksheet.Save()
Else
Dim row As Row = rows.First()
Dim cells As IEnumerable(Of Cell) = row.Elements(Of Cell)().Where(Function(c) c.CellReference.Value = cellName)

' If the row does not contain the specified cell, create the specified cell.
If (cells.Count = 0) Then
Dim cell As Cell = New Cell
cell.CellReference = New StringValue(cellName)

row.Append(cell)
worksheet.Save()
End If
End If
End Sub

' Given a cell name, parses the specified cell to get the column name.
Private Function GetColumnName(ByVal cellName As String) As String
' Create a regular expression to match the column name portion of the cell name.
Dim regex As Regex = New Regex("[A-Za-z]+")
Dim match As Match = regex.Match(cellName)
Return match.Value
End Function

' Given a cell name, parses the specified cell to get the row index.
Private Function GetRowIndex(ByVal cellName As String) As UInteger
' Create a regular expression to match the row index portion the cell name.
Dim regex As Regex = New Regex("\d+")
Dim match As Match = regex.Match(cellName)
Return UInteger.Parse(match.Value)
End Function

Siehe auch

Referenz

Class Library Reference

Sonstige Ressourcen

Sprachintegrierte Abfrage (Language-Integrated Query, LINQ)

Lambda-Ausdrücke

Lambda-Ausdrücke (C#-Programmierhandbuch)