Afdrukgebied instellen - OpenXML met Excel

Weet iemand hoe het afdrukgebied via OpenXML SDK in Excel moet worden ingesteld?

Ik heb geprobeerd de volgende code te gebruiken:

public void XLUpdateDefinedName(string fileName, string definedName, string newRange)
{
    using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, true))
    {
        WorkbookPart wbPart = document.WorkbookPart;

        var definedNames = wbPart.Workbook.Descendants().FirstOrDefault();
        DefinedName name = definedNames.Descendants().Where(m => m.Name == definedName).Single();
        UInt32Value locSheetId = name.LocalSheetId;
        name = null;//.Remove();
        wbPart.Workbook.Save();
        name = new DefinedName() { Name = definedName, LocalSheetId = locSheetId , Text = newRange}
            ;
        wbPart.Workbook.Save();
        //newDefinedName.Text = newRange;
        //definedNames.Append(newDefinedName);

    }
}

UPDATE:

Ik blijf een foutmelding ontvangen van excel met de melding dat er een onleesbare inhoud in het bestand is met de volgende code.

   public void XLUpdateDefinedName(string fileName, string definedName, string newRange, string sheet, UInt32Value localId)
    {
        using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, true))
        {                
            String sheetName = sheet;
            string topLeft = newRange.Split(':').First();
            string bottomRight = newRange.Split(':').Last();
            WorkbookPart wbPart = document.WorkbookPart;

            var definedNames = wbPart.Workbook.Descendants().FirstOrDefault();
            var nameCollection = definedNames.Descendants().Where(m => m.Text.StartsWith(sheetName));
            DefinedName name = nameCollection.Count() > 0 ? nameCollection.First() : null;
            UInt32Value locSheetId;
            if (name != null)
            {
                locSheetId = name.LocalSheetId;
                name.Remove();
                wbPart.Workbook.Save();
            }
            else
            {
                locSheetId = localId;
            }
            name = new DefinedName() { Name = "_xlnm.Print_Area", LocalSheetId = locSheetId};
            name.Text = String.Format("{0}!{1}:{2}", sheetName,topLeft,bottomRight);
            definedNames.Append(name);
            wbPart.Workbook.Save();
        }}

newRange heeft de vorm ($ A $ 10: $ C $ 15)

2
Uw code werkt correct. Als u een bestaande afdruktaak wijzigt of een afdrukgebieddefinitie toevoegt voor een werkblad in het document waarvoor ten minste één afdrukgebied al is gedefinieerd. Dit komt waarschijnlijk omdat er een aantal andere elementen zijn toegevoegd bij het maken van de eerste afdrukgebieddefinitie in een werkmap. Om het te laten werken, moet je gewoon een sjabloon gebruiken met één reeds gedefinieerd afdrukgebied. U kunt ook localId en definedName van de parameters van de methode verwijderen.
toegevoegd de auteur Lukasz M, de bron
als het met behulp van vb-automatisering is gebeurd, waarom zou u OleAutomation niet gebruiken beter bekend als Interop of Com-Interop, dat wil zeggen als u codeert in C #
toegevoegd de auteur MethodMan, de bron
probeer deze link het kan al dan niet helpen .. zorg ervoor dat je de hele pagina bekijkt die het voorbeelden geeft .. msdn.microsoft.com/en-us/library/cc540662 (office.12) .aspx
toegevoegd de auteur MethodMan, de bron
Mijn huidige taak is het verwijderen van de afhankelijkheid van een Excel-invoegtoepassing van Com-Interop. Mijn bedrijf gebruikt een aangepaste berekeningsengine bovenop Excel en met behulp van interop zorgt Excel ervoor dat berekeningen worden uitgeschakeld die echt niet nodig zijn. Het eindresultaat is een eenvoudige tool die heel lang duurt om een ​​relatief eenvoudige taak te voltooien. Door interop te verwijderen, kan ik een Excel-document manipuleren via Open xml en één berekening uitvoeren aan het einde van alle wijzigingen aan dat document, waardoor de tijd om de taak te voltooien aanzienlijk wordt verkort.
toegevoegd de auteur M4V3R1CK, de bron
Bedankt voor de suggestie, maar heb dat feitelijk gevonden en gebruikt VB Automation voor het instellen van het afdrukgebied. Ik moet een afdrukgebied behouden op een werkblad dat ik kopieer naar een nieuwe werkmap, en ik zou het graag willen bereiken met Open xml indien mogelijk om mijn applicatie consistent te houden.
toegevoegd de auteur M4V3R1CK, de bron

2 antwoord

Ik heb wat informatie gevonden over een methode die Interop niet lijkt te gebruiken. Je kunt iets proberen als:

//load the work book
...

myWorkBook.Worksheets.First().PageSetup.PrintAreas.Add("A1:F40");

//save the workbook
//...

Kijk of dit helpt. Ik heb het zelf nog niet geprobeerd, maar ik ga het verifiëren.

UPDATE: The first method seems to require an additional library. You can get it from here: http://closedxml.codeplex.com/. I haven't used it myself, so I cannot assure you it works correctly.

Pure OpenXML-oplossing

Ik ben erin geslaagd het afdrukgebied te wijzigen door de xlsx-bestandsinhoud handmatig aan te passen in de Kladblokeditor.

In C# zou je moeten proberen de volgende methode te gebruiken (het zet het afdrukgebied op A1: G19 ):

//first you need to get reference to your workbook, but I assume you already have this
//...
//then you can add an information about desired print area
DefinedNames definedNames = new DefinedNames();
DefinedName printAreaDefName = new DefinedName() { Name = "_xlnm.Print_Area", LocalSheetId = (UInt32Value)0U };
printAreaDefName.Text = "Worksheet1!$A$1:$G$19";
definedNames.Append(printAreaDefName);
//then you should append the created element to your workbook
//...
workbook1.Append(definedNames);

Het ding dat je moet veranderen is regel: printAreaDefName.Text = "Werkblad1! $ A $ 1: $ G $ 19"; .

U moet de tekstwaarde zodanig wijzigen dat deze informatie de volgende indeling heeft: [werkbladnaam]! [Linkerbovenhoek van afdrukgebied]: [rechteronderhoek van afdrukgebied] . Het moet uw afdrukgebied instellen op een rechthoek met de linkerbovenhoek en de rechteronderhoek zoals opgegeven.

Als u afdrukgebieden voor verschillende werkbladen wilt opgeven, probeert u meerdere DefinedName -objecten toe te voegen:

  DefinedName printAreaDefName = new DefinedName() { Name = "_xlnm.Print_Area", LocalSheetId = (UInt32Value)0U };
  printAreaDefName.Text = "Worksheet1!$A$1:$G$19";
  definedNames.Append(printAreaDefName);
  DefinedName printAreaDefName2 = new DefinedName() { Name = "_xlnm.Print_Area", LocalSheetId = (UInt32Value)1U };
  printAreaDefName2.Text = "Worksheet2!$B$1:$H$23";
  definedNames.Append(printAreaDefName2);
  DefinedName printAreaDefName3 = new DefinedName() { Name = "_xlnm.Print_Area", LocalSheetId = (UInt32Value)2U };
  printAreaDefName3.Text = "Worksheet3!$A$1:$J$10";
  definedNames.Append(printAreaDefName3);

I also recommend using OpenXML SDK 2.0 Productivity Tool. It allows you to show the contents of a chosen OpenXML file, compare files, validate a file and even show a C# code that you would write in order to recreate the file programatically :). You can download it from here: http://www.microsoft.com/download/en/details.aspx?id=5124

UPDATE II:

Ik heb een fout gecorrigeerd in de opmaak van de tekenreeks voor de afdrukruimte. Sorry voor de verwarring. Ik heb ook de code die je gepost hebt genomen en een methode gemaakt die daarop is gebaseerd. Het werkt correct en na het aanpassen van het afdrukgebied kan ik het bestand zonder problemen openen in Excel. De code gaat ervan uit dat een afdrukbereik al is gedefinieerd en dat u deze nu alleen maar wijzigt, maar het kan ook worden gewijzigd om een ​​nieuw afdrukbereik toe te voegen. Hier is de code:

private void OpenXmlFileHandling(String fileName)
    {
        using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, true))
        {
            //some sample values
            String definedName = "Worksheet3";
            String topLeft = "$A$3";
            String bottomRight = "$D$7";

            WorkbookPart wbPart = document.WorkbookPart;

            var definedNames = wbPart.Workbook.Descendants().FirstOrDefault();
            var namesCollection = definedNames.Descendants().Where(m => m.Text.StartsWith(definedName));
            DefinedName name = namesCollection != null ? namesCollection.First() : null;

            UInt32Value locSheetId;
            //we assume that name is not null, because print range for this worksheet was defined in the source template file
            //if name was null, we should probably just assign to locSheetId a number definedNames.Count() + 1 and not remove the name node
            locSheetId = name.LocalSheetId;
            name.Remove();

            wbPart.Workbook.Save();
            name = new DefinedName() { Name = "_xlnm.Print_Area", LocalSheetId = locSheetId, Text = String.Format("{0}!{1}:{2}", definedName, topLeft, bottomRight) };


            definedNames.Append(name);

            wbPart.Workbook.Save();
        }
    }

Ik plaats de waarden van de werkbladnaam en het bereik van het afdrukgebied in de methode, zodat u kunt zien wat voor soort waarden ze moeten hebben. Ik hoop dat dit helpt.

2
toegevoegd
Ik raad u aan de substructuur DefinedName-knooppunten toe te voegen als deze ontbreekt. Bereken alle gedefinieerde DefinedName-knooppunten, voeg 1 toe en wijs deze waarde toe aan locSheetId. Dit zou het werk moeten doen. Maar zorg er eerst voor dat het werkt als printarea eerder is gedefinieerd, indien mogelijk.
toegevoegd de auteur Lukasz M, de bron
Ja, de code werkt als u eerder het afdrukgebied in de sjabloon hebt gedefinieerd en deze nu alleen maar naar een andere waarde wijzigt.
toegevoegd de auteur Lukasz M, de bron
Ik zag het en update dit antwoord ermee. Ik nam je code en paste hem aan om een ​​methode in het antwoord te krijgen. Bekijk het stukcodefragment en corrigeer uw code op basis daarvan. Lees sectie UPDATE II.
toegevoegd de auteur Lukasz M, de bron
Ik denk dat ik heb ontdekt hoe het nu is, maar vertel me dat je altijd hetzelfde afdrukgebied moet instellen of moet bepalen wat het dynamisch is.
toegevoegd de auteur Lukasz M, de bron
Ik heb het tekstformaat dat je zou moeten invoegen gecorrigeerd. Het moet in werkblad 1! $ A: $ 10 zijn.
toegevoegd de auteur Lukasz M, de bron
Het antwoord bijgewerkt om een ​​voorbeeld te tonen voor meerdere werkbladen.
toegevoegd de auteur Lukasz M, de bron
Bedankt Lucas! Hulp zeer op prijs gesteld!
toegevoegd de auteur M4V3R1CK, de bron
Dit is waar ik een probleem heb, denk ik. Ik gebruik een sjabloon met slechts één vel en één afdrukgebied. Ik kopieer dat vel nu x keer in een andere werkmap en voeg het afdrukgebied toe aan de nieuwe bladen zonder dat het al bestond ...
toegevoegd de auteur M4V3R1CK, de bron
wanneer u de localsheetid instelt, zal dat mislukken als de naam null is. bedankt voor je hulp
toegevoegd de auteur M4V3R1CK, de bron
Heb je mijn update gezien? Ik heb geen idee waarom ik de fout krijg als ik open in Excel. Ik open met de OpenXml Validator Tool en er zijn geen validatiefouten, maar het openen van Excel geeft me een onleesbare inhoudfout
toegevoegd de auteur M4V3R1CK, de bron
Blijf ook corrupte gegevens ontvangen!?!?!? Frustrerend voor zo'n eenvoudige taak.
toegevoegd de auteur M4V3R1CK, de bron
Nog een ding. Uit de bovenstaande code lijkt het alsof het afdrukgebied werkbladspecifiek is. Ik wil niet noodzakelijk een afdrukgebied opgeven voor een specifiek werkblad, maar een afdrukgebied instellen dat zich uitstrekt over veel werkbladen in een werkmap. Dus als ik een werkmap met 10 werkbladen heb, moet een afdruk elk werkblad met hetzelfde gedefinieerde bereik afdrukken. Dus, als ik de naam van het specifieke werkblad verwijder en alleen een bereik (A1: C50) heb, zal het dan werken zoals gewenst?
toegevoegd de auteur M4V3R1CK, de bron
Ik moet het instellen op basis van een sjabloonwerkblad. (dat wil zeggen, bepaal het afdrukgebied van de sjabloon en stel het x aantal keren in voor elk werkblad dat ik kopieer vanuit de sjabloon.
toegevoegd de auteur M4V3R1CK, de bron
Opmerking over update: hoe wordt de PrintArea gewijzigd of ingesteld?
toegevoegd de auteur M4V3R1CK, de bron
Niet zozeer ... Dit moet een andere bibliotheek gebruiken
toegevoegd de auteur M4V3R1CK, de bron
Dit ziet er echt veelbelovend uit. Ik zal je op de hoogte houden. Bedankt
toegevoegd de auteur M4V3R1CK, de bron

Laat me mijn case uitleggen: ik heb een Excel-werkmap met de volgende sheets (T1, I1, M1). Nu was mijn vereiste gebaseerd op een voorwaarde T1, I1, M1 zal meerdere keren worden gekopieerd naar dezelfde Excel-werkmap, bijvoorbeeld T2, I2, M2, T3, I3, M3 enzovoort. Voor mij I2 had M2 geen problemen met het Print-gebied, maar voor gekopieerd vel had T2, T3 ... problemen. omdat het enorme gegevens had. excel kolom gaat tot "AG". Dus hier is wat ik deed in de code

Zodra het nieuwe blad is toegevoegd aan de werkmap

sheets.Append(copiedSheet);

verkrijg eerst het huidige aantal vellen

var count = sheets.Count(); 

Verkrijg het aantal vellen, dit wordt gebruikt in LocalsheetId als printarea-instelling.

Alleen voor gekopieerd technisch blad was het afdrukgebied niet goed ingesteld. Daarom moet het correct worden ingesteld.

DefinedName printAreaDefName = new DefinedName() { Name = "_xlnm.Print_Area", LocalSheetId = Convert.ToUInt32(count) };

Wees voorzichtig met defName.Text het formaat is 'T1'! $ A $ 1: $ AG $ 19

printAreaDefName.Text = "'" + copiedSheet.Name + "'!$A$1:$AG$22";

workbookPart.Workbook.DefinedNames.Append(printAreaDefName); 
workbookPart.Workbook.Save();

Het was niet nodig om nieuwe Definedname toe te voegen in de DefinedNames-verzameling. Dus ik heb zojuist aan de map werkmap definedNames toegevoegd en het werkte.

0
toegevoegd