Как программно создавать документы Word из шаблона - PullRequest
17 голосов
/ 29 ноября 2010

Я пытаюсь создать около 600 отчетов в Microsoft Office Word.Документы заполняются данными из базы данных, а изображения находятся на локальном диске.Я понял, что мог бы создать проект Word Template в Visual Studio 2010 и запрограммировать шаблон так, чтобы при вводе одного значения (id-номера) он автоматически заполнял весь документ.

Я совершенно уверен, что это возможно.Единственная проблемаКак мне перебрать все записи в базе данных, открыть новый документ на основе шаблона и установить значение id?

for(int i = 0; i < idnumbers.Count(); i++)
{
     Word.Application app = new Word.Application();
     Word.Document doc = app.Documents.Add(@"C:\..\WordGenerator\bin\Debug\WordTemplate.dotx");
     //input the id-number below: HOW??

     doc.SaveAs(FileName: @"c:\temp\test.docx"); 
}

Приложение должно запускаться только один раз, генерируя отчеты, и ононе должен быть быстрымЭто просто должно быть легко разработать.

Проблема здесь в том, что кажется, что объект DocumentBase недоступен вне проекта Word.Заменяющий Microsoft.Office.Interop.Word.Document не имеет такой функциональности, как SelectContentControlsByTitle, которая позволяет мне находить и устанавливать мои ContentControls.И это именно то, что мне нужно сделать ..

Вот как теперь выглядит мой код для вставки текста в мое поле: Word.Application app = new Word.Application ();

        Word.Document doc = app.Documents.Add(@"C:\..\test.dotx");

        foreach (Word.ContentControl cc in doc.SelectContentControlsByTitle("MyCCTitle"))
        {
            cc.Range.Text += "1234";
        }

        doc.SaveAs(FileName: @"c:\temp\test.docx");

Затем обработчик событий в моем шаблоне BeforeSave заполняет документ на основе текста в объекте с названием MyCCTitle.

Ответы [ 6 ]

12 голосов
/ 29 ноября 2010

Не используйте Office Automation.Автоматизация офиса открывает экземпляр офиса в фоновом режиме и выполняет действия над ним.Открытие офисного экземпляра 600 раз не кажется очень интересным занятием.(и он никогда не будет работать на стороне сервера)

Взгляните на Open XML.Об этом вы можете узнать ниже:

http://openxmldeveloper.org/

edit: Openxmldeveloper закрывается.Найдите все источники, упомянутые выше, по адресу http://www.ericwhite.com/.

6 голосов
/ 30 ноября 2010

Может быть, вы должны смотреть на Microsoft.Office.Tools.Word.Document?

Document.SelectContentControlsByTitle

5 голосов
/ 29 ноября 2010

Вам следует прочитать о формате OpenXML, если вы используете формат Word 2007 или 2010

http://msdn.microsoft.com/en-us/library/bb264572(office.12).aspx

3 голосов
/ 30 ноября 2010

Похоже, что здесь есть 2 вопроса:

  1. Как начать процесс для определенного значения идентификатора

  2. Как сделатьВы заполняете документ.

Sunilp ответил Q2.Элементы управления содержимым с привязкой к данным - лучший способ внедрить данные для Word 2007 и более поздних версий.

Фокус OP выглядит как Q1.

Нет переключателя командной строки, который позволял бы передавать произвольное значение в Word: http://support.microsoft.com/kb/210565

Так что, как я вижу, у вас есть 4 варианта:

  1. делать всю работу через OpenXML SDK, никогда не открывая Word вообще (как предлагали другие авторы)

  2. создать минимальный ранее существующий документ (содержащий ваш идентификационный номер), используяOpenXML SDk, затем откройте Word

  3. , чтобы автоматизировать Word, чтобы передать идентификационный номер в документ, возможно, в качестве свойства документа

  4. выполнить работусоздать 600 документов в Word с помощью макросов VSTO или Word (VBA)

Me?Я бы создал документ, содержащий элементы управления содержимым в Word, и сохранил бы его.

Затем он вставил бы мои данные в него как пользовательскую часть XML и сохранил его.(Этот шаг вы можете выполнить с помощью OpenXML SDK или в Word, если вам нужно, чтобы Word обновил привязки для какого-либо из ваших последующих процессов)

0 голосов
/ 27 января 2015

Добавить ссылки для Document.OpenXml.dll и WindowsBase.dll

using System.IO.Packaging;

using DocumentFormat.OpenXml.Packaging;

using System.DirectoryServices;

 protected void btnOK_Click(object sender, EventArgs e)
  {

        try
        {
            Package package;
            string strTemplateName = ddl_Templates.SelectedValue.ToString(); //Select Dotx template 
            string strClaimNo = "3284112";
            string strDatePart = DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + DateTime.Now.Day.ToString() + DateTime.Now.Hour.ToString() + DateTime.Now.Minute.ToString() + DateTime.Now.Second.ToString() + DateTime.Now.Millisecond.ToString();
            //Word template file
            string templateName = Server.MapPath("~\\LetterTemplates\\" + strTemplateName + ".dotx");
            PackagePart documentPart = null;
            //New file name to be generated from 
            string docFileName = Server.MapPath("~\\LetterTemplates\\" + strClaimNo + "_" + strTemplateName + "_" + strDatePart + ".docx");

            File.Copy(templateName,docFileName, true);
            string fileName = docFileName;
            package = Package.Open(fileName, FileMode.Open, FileAccess.ReadWrite);
            DataSet DS = GetDataSet(strClaimNo, ""); // to get the data from backend to fill in for merge fields
            try
            {
                if (DS != null)
                {
                    if (DS.Tables.Count > 0)
                    {
                        if (DS.Tables[0].Rows.Count > 0)
                        {
                            foreach (System.IO.Packaging.PackageRelationship documentRelationship
                                in package.GetRelationshipsByType(documentRelationshipType))
                            {
                                NameTable nt = new NameTable();
                                nsManager = new XmlNamespaceManager(nt);
                                nsManager.AddNamespace("w",
                                  "http://schemas.openxmlformats.org/wordprocessingml/2006/main");

                                Uri documentUri = PackUriHelper.ResolvePartUri(
                                  new Uri("/", UriKind.Relative), documentRelationship.TargetUri);
                                documentPart = package.GetPart(documentUri);

                                //Get document xml
                                XmlDocument xdoc = new XmlDocument();
                                xdoc.Load(documentPart.GetStream(FileMode.Open, FileAccess.Read));
                                int intMergeFirldCount = xdoc.SelectNodes("//w:t", nsManager).Count;

                                XmlNodeList nodeList = xdoc.SelectNodes("//w:t", nsManager);
                                foreach (XmlNode node in nodeList)
                                {
                                    try
                                    {
                                        xdoc.InnerXml = xdoc.InnerXml.Replace(node.InnerText, DS.Tables[0].Rows[0][node.InnerText.Replace("«", "").Replace("»", "").Trim()].ToString());
                                    }catch(Exception x) { }
                                }

                                StreamWriter streamPart = new StreamWriter(documentPart.GetStream(FileMode.Open, FileAccess.Write));
                                xdoc.Save(streamPart);
                                streamPart.Close();
                                package.Flush();
                                package.Close();
                            }
                            using (WordprocessingDocument template = WordprocessingDocument.Open(docFileName, true))
                            {
                                template.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document);
                                template.MainDocumentPart.Document.Save();
                            }

                            byte[] bytes = System.IO.File.ReadAllBytes(docFileName);
                            System.IO.File.Delete(docFileName);
                            System.Web.HttpResponse response = System.Web.HttpContext.Current.Response;
                            response.ClearContent();
                            response.Clear();
                            response.ContentType = "application/vnd.msword.document.12"; //"application/msword";
                            Response.ContentEncoding = System.Text.Encoding.UTF8;
                            response.AddHeader("Content-Disposition", "attachment; filename=" + strClaimNo + "_" + strTemplateName + "_" + strDatePart + ".docx;");
                            response.BinaryWrite(bytes);
                            response.Flush();
                            response.Close();
                        }
                        else
                        {
                            throw (new Exception("No Records Found."));
                        }
                    }
                    else
                    {
                        throw (new Exception("No Records Found."));
                    }
                }
                else
                {
                    throw (new Exception("No Records Found."));
                }


            }
            catch (Exception ex)
            {
                package.Flush();
                package.Close();
                // Softronic to add code for exception handling
            }
        }
        catch (Exception ex)
        {

            // add code for exception handling
        }
        finally
        {

        }
    }
0 голосов
/ 03 декабря 2014

Что касается ответов выше, я согласен с J. Vermeire, что OpenXML - это путь. Уже более трех лет я использую инструментарий на основе OpenXML, который создает документы .docx, объединенные из шаблонов и данных базы данных. Вот пример, как его использовать здесь . В примере показано, как работать с одним документом за раз, чтобы работать с большим количеством из них, просто добавьте цикл и вызовите метод для создания документа.

...