سؤال

باستخدام OpenXML SDK ، 2.0 CTP ، أحاول إنشاء مستند Word برمجيًا. في وثيقتي ، يجب أن أدخل قائمة نقطية ، يجب التأكيد على بعض عناصر القائمة. كيف يمكنني أن أفعل هذا؟

هل كانت مفيدة؟

المحلول

القوائم في OpenXML مربكة بعض الشيء.

هناك numberingDefinitionSpart الذي يصف جميع القوائم في المستند. أنه يحتوي على معلومات حول كيفية ظهور القوائم (نقطية ، مرقمة ، إلخ) ، ويعين أيضًا ومعرف كل واحدة.

ثم في MainDocumentPart, ، لكل عنصر في القائمة التي تريد إنشاؤها ، يمكنك إضافة فقرة جديدة وتعيين معرف القائمة التي تريد تلك الفقرة.

لإنشاء قائمة رصاصة مثل:

  • مرحبًا،
  • العالمية!

يجب عليك أولاً إنشاء numningDefinitionSpart:

NumberingDefinitionsPart numberingPart =
  mainDocumentPart.AddNewPart<NumberingDefinitionsPart>("someUniqueIdHere");

Numbering element = 
  new Numbering(
    new AbstractNum(
      new Level(
        new NumberingFormat() {Val = NumberFormatValues.Bullet},
        new LevelText() {Val = "·"}
      ) {LevelIndex = 0}
    ){AbstractNumberId = 1},
    new NumberingInstance(
      new AbstractNumId(){Val = 1}
    ){NumberID = 1});

element.Save(numberingPart);

ثم تقوم بإنشاء MainDocumentPart كما تفعل عادة ، باستثناء خصائص الفقرة ، تعيين معرف الترقيم:

MainDocumentPart mainDocumentPart =
  package.AddMainDocumentPart();

Document element = 
  new Document(
    new Body(
      new Paragraph(
        new ParagraphProperties(
          new NumberingProperties(
            new NumberingLevelReference(){ Val = 0 },
            new NumberingId(){ Val = 1 })),
        new Run(
          new RunProperties(),
          new Text("Hello, "){ Space = "preserve" })),
      new Paragraph(
        new ParagraphProperties(
          new NumberingProperties(
            new NumberingLevelReference(){ Val = 0 },
            new NumberingId(){ Val = 1 })),
        new Run(
          new RunProperties(),
          new Text("world!"){ Space = "preserve" }))));

element.Save(mainDocumentPart);

هناك تفسير أفضل للخيارات المتاحة في دليل مرجعي OpenXML في القسم 2.9.

نصائح أخرى

أردت شيئًا يسمح لي بإضافة أكثر من قائمة رصاصة إلى مستند. بعد ضجيج رأسي على مكتبي لفترة من الوقت ، تمكنت من الجمع بين مجموعة من المنشورات المختلفة وفحص المستند الخاص بي مع أداة منتجات XML SDK 2.0 المفتوحة وتصورت بعض الأشياء. المستند الذي تنتجه الآن يمرر التحقق من صحة عن طريق الإصدار 2.0 و 2.5 من أداة إنتاجية SDK.

هنا هو الرمز. نأمل أن ينقذ شخص ما بعض الوقت وتفاقم.

الاستخدام:

const string fileToCreate = "C:\\temp\\bulletTest.docx";

 if (File.Exists(fileToCreate))
    File.Delete(fileToCreate);

var writer = new SimpleDocumentWriter();
List<string> fruitList = new List<string>() { "Apple", "Banana", "Carrot"};
writer.AddBulletList(fruitList);
writer.AddParagraph("This is a spacing paragraph 1.");

List<string> animalList = new List<string>() { "Dog", "Cat", "Bear" };
writer.AddBulletList(animalList);
writer.AddParagraph("This is a spacing paragraph 2.");

List<string> stuffList = new List<string>() { "Ball", "Wallet", "Phone" };
writer.AddBulletList(stuffList);
writer.AddParagraph("Done.");

writer.SaveToFile(fileToCreate);

باستخدام البيانات:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;    

شفرة

public class SimpleDocumentWriter : IDisposable
{
    private MemoryStream _ms;
    private WordprocessingDocument _wordprocessingDocument;

    public SimpleDocumentWriter()
    {
        _ms = new MemoryStream();
        _wordprocessingDocument = WordprocessingDocument.Create(_ms, WordprocessingDocumentType.Document);
        var mainDocumentPart = _wordprocessingDocument.AddMainDocumentPart();
        Body body = new Body();
        mainDocumentPart.Document = new Document(body);
    }

    public void AddParagraph(string sentence)
    {
        List<Run> runList = ListOfStringToRunList(new List<string> { sentence});
        AddParagraph(runList);
    }
    public void AddParagraph(List<string> sentences)
    {
        List<Run> runList = ListOfStringToRunList(sentences);
        AddParagraph(runList);
    }

    public void AddParagraph(List<Run> runList)
    {
        var para = new Paragraph();
        foreach (Run runItem in runList)
        {
            para.AppendChild(runItem);
        }

        Body body = _wordprocessingDocument.MainDocumentPart.Document.Body;
        body.AppendChild(para);
    }

    public void AddBulletList(List<string> sentences)
    {
        var runList = ListOfStringToRunList(sentences);

        AddBulletList(runList);
    }


    public void AddBulletList(List<Run> runList)
    {
        // Introduce bulleted numbering in case it will be needed at some point
        NumberingDefinitionsPart numberingPart = _wordprocessingDocument.MainDocumentPart.NumberingDefinitionsPart;
        if (numberingPart == null)
        {
            numberingPart = _wordprocessingDocument.MainDocumentPart.AddNewPart<NumberingDefinitionsPart>("NumberingDefinitionsPart001");
            Numbering element = new Numbering();
            element.Save(numberingPart);
        }

        // Insert an AbstractNum into the numbering part numbering list.  The order seems to matter or it will not pass the 
        // Open XML SDK Productity Tools validation test.  AbstractNum comes first and then NumberingInstance and we want to
        // insert this AFTER the last AbstractNum and BEFORE the first NumberingInstance or we will get a validation error.
        var abstractNumberId = numberingPart.Numbering.Elements<AbstractNum>().Count() + 1;
        var abstractLevel = new Level(new NumberingFormat() {Val = NumberFormatValues.Bullet}, new LevelText() {Val = "·"}) {LevelIndex = 0};
        var abstractNum1 = new AbstractNum(abstractLevel) {AbstractNumberId = abstractNumberId};

        if (abstractNumberId == 1)
        {
            numberingPart.Numbering.Append(abstractNum1);
        }
        else
        {
            AbstractNum lastAbstractNum = numberingPart.Numbering.Elements<AbstractNum>().Last();
            numberingPart.Numbering.InsertAfter(abstractNum1, lastAbstractNum);
        }

        // Insert an NumberingInstance into the numbering part numbering list.  The order seems to matter or it will not pass the 
        // Open XML SDK Productity Tools validation test.  AbstractNum comes first and then NumberingInstance and we want to
        // insert this AFTER the last NumberingInstance and AFTER all the AbstractNum entries or we will get a validation error.
        var numberId = numberingPart.Numbering.Elements<NumberingInstance>().Count() + 1;
        NumberingInstance numberingInstance1 = new NumberingInstance() {NumberID = numberId};
        AbstractNumId abstractNumId1 = new AbstractNumId() {Val = abstractNumberId};
        numberingInstance1.Append(abstractNumId1);

        if (numberId == 1)
        {
            numberingPart.Numbering.Append(numberingInstance1);
        }
        else
        {
            var lastNumberingInstance = numberingPart.Numbering.Elements<NumberingInstance>().Last();
            numberingPart.Numbering.InsertAfter(numberingInstance1, lastNumberingInstance);
        }

        Body body = _wordprocessingDocument.MainDocumentPart.Document.Body;

        foreach (Run runItem in runList)
        {
            // Create items for paragraph properties
            var numberingProperties = new NumberingProperties(new NumberingLevelReference() {Val = 0}, new NumberingId() {Val = numberId});
            var spacingBetweenLines1 = new SpacingBetweenLines() { After = "0" };  // Get rid of space between bullets
            var indentation = new Indentation() { Left = "720", Hanging = "360" };  // correct indentation 

            ParagraphMarkRunProperties paragraphMarkRunProperties1 = new ParagraphMarkRunProperties();
            RunFonts runFonts1 = new RunFonts() { Ascii = "Symbol", HighAnsi = "Symbol" };
            paragraphMarkRunProperties1.Append(runFonts1);

            // create paragraph properties
            var paragraphProperties = new ParagraphProperties(numberingProperties, spacingBetweenLines1, indentation, paragraphMarkRunProperties1);

            // Create paragraph 
            var newPara = new Paragraph(paragraphProperties);

            // Add run to the paragraph
            newPara.AppendChild(runItem);

            // Add one bullet item to the body
            body.AppendChild(newPara);
        }
    }


    public void Dispose()
    {
        CloseAndDisposeOfDocument();
        if (_ms != null)
        {
            _ms.Dispose();
            _ms = null;
        }
    }

    public MemoryStream SaveToStream()
    {
        _ms.Position = 0;
        return _ms;
    }

    public void SaveToFile(string fileName)
    {
        if (_wordprocessingDocument != null)
        {
            CloseAndDisposeOfDocument();
        }

        if (_ms == null)
            throw new ArgumentException("This object has already been disposed of so you cannot save it!");

        using (var fs = File.Create(fileName))
        {
            _ms.WriteTo(fs);
        }
    }

    private void CloseAndDisposeOfDocument()
    {
        if (_wordprocessingDocument != null)
        {
            _wordprocessingDocument.Close();
            _wordprocessingDocument.Dispose();
            _wordprocessingDocument = null;
        }
    }

    private static List<Run> ListOfStringToRunList(List<string> sentences)
    {
        var runList = new List<Run>();
        foreach (string item in sentences)
        {
            var newRun = new Run();
            newRun.AppendChild(new Text(item));
            runList.Add(newRun);
        }

        return runList;
    }
}

إجابة آدم أعلاه صحيحة باستثناء أنها تردد جديد (بدلاً من NUM جديد (كما هو مذكور في التعليق.

بالإضافة إلى ذلك ، إذا كان لديك قوائم متعددة ، فيجب أن يكون لديك عناصر ترقيم متعددة (لكل منها معرف خاص به على سبيل المثال 1 و 2 و 3 وما إلى ذلك - واحدة لكل قائمة في المستند. لا يبدو أن هذا يمثل مشكلة في قوائم الرصاص ، لكن القوائم المرقمة ستستمر في استخدام نفس تسلسل الترقيم (كما في مقابل البدء من جديد في 1) لأنها ستعتقد أنها نفس القائمة. يجب الرجوع إلى الرقم في فقرتك مثل هذه:

ParagraphProperties paragraphProperties1 = new ParagraphProperties();
ParagraphStyleId paragraphStyleId1 = new ParagraphStyleId() { Val = "ListParagraph" };
NumberingProperties numberingProperties1 = new NumberingProperties();
NumberingLevelReference numberingLevelReference1 = new NumberingLevelReference() { Val = 0 };

NumberingId numberingId1 = new NumberingId(){ Val = 1 }; //Val is 1, 2, 3 etc based on your numberingid in your numbering element
numberingProperties1.Append(numberingLevelReference1);
numberingProperties1.Append(numberingId1);
paragraphProperties1.Append(paragraphStyleId1);
paragraphProperties1.Append(numberingProperties1);

سيكون للأطفال من عنصر المستوى تأثير على نوع الرصاصة ، والمسافة البادئة. كانت رصاصاتي صغيرة جدًا حتى أضفت هذا إلى عنصر المستوى:

new NumberingSymbolRunProperties(
    new RunFonts() { Hint = FontTypeHintValues.Default, Ascii = "Symbol", HighAnsi =   "Symbol" })

كان المسافة البادئة مشكلة حتى أضفت هذا العنصر إلى عنصر المستوى أيضًا:

new PreviousParagraphProperties(
  new Indentation() { Left = "864", Hanging = "360" })

وإذا كنت مثلي - إنشاء مستند من قالب ، فقد ترغب في استخدام هذا الرمز ، للتعامل مع كلتا الحالتين - عندما لا يحتوي القالب أو لا يحتوي على أي تعريفات ترقيم:

// Introduce bulleted numbering in case it will be needed at some point
NumberingDefinitionsPart numberingPart = document.MainDocumentPart.NumberingDefinitionsPart;
if (numberingPart == null)
{
    numberingPart = document.MainDocumentPart.AddNewPart<NumberingDefinitionsPart>("NumberingDefinitionsPart001");
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top