2010-11-29 2 views
14

Je suis en train de créer environ 600 rapports dans Microsoft Office Word. Les documents sont remplis avec des données provenant d'une base de données et des images trouvées sur un lecteur local. J'ai compris, que je pourrais créer un projet Word Template dans Visual Studio 2010, et programmer le modèle, de sorte que lorsque vous entrez une seule valeur (numéro d'identification), il remplit automatiquement le document entier.Comment créer des documents Word par programme à partir d'un modèle

Je suis assez confiant que c'est possible. le seul problème est. Comment parcourir toutes les entrées de la base de données, ouvrir un nouveau document basé sur le modèle et définir la valeur d'id? L'application est supposée ne s'exécuter qu'une seule fois, générant les rapports, et elle n'a pas besoin d'être rapide. Il doit juste être facile à développer.

Le problème ici est qu'il semble que l'objet DocumentBase n'est pas accessible en dehors du projet Word. Le substitut Microsoft.Office.Interop.Word.Document n'a pas de fonctionnalité comme SelectContentControlsByTitle qui me permet de trouver et de définir mes ContentControls. Et c'est exactement ce que j'ai besoin de faire ..

Voici à quoi ressemble mon code maintenant pour insérer le texte dans mon champ: 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"); 

Puis un eventhandler sur mon modèle sur BeforeSave remplit le document sur la base du texte objet intitulé MyCCTitle.

Répondre

3

Peut-être devriez-vous regarder Microsoft.Office.Tools.Word.Document?

Document.SelectContentControlsByTitle

+0

Enfin, j'ai découvert que c'était en fait la voie à suivre .. Mais il y a beaucoup de choses dont vous devez être conscient. Tout d'abord, vous devez ajouter une référence au composant nommé office et vous devez faire en sorte que vos assemblys soient la bonne version, sinon vous n'aurez pas accès aux méthodes et aux objets corrects. –

4

Vous devriez lire sur le format OpenXML si vous utilisez Word 2007 ou 2010 Format

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

+0

ce serait trop pour ce qu'il tente de réaliser, l'automatisation Word/Interop est beaucoup plus facile à faire pour ce scénario. – BrokenGlass

+0

Surcharge? Pas du tout. Le SDK OpenXML est facile à utiliser et est censé faire exactement cela. Vous n'avez pas besoin d'avoir Word installé sur votre serveur lors de l'automatisation des mots/interop? Avec OpenXML, vous ne le faites pas. –

+0

Plus je veux ajouter au commentaire Moontear, format OpenXML est juste XML il si vite à ce qu'il essaie de faire (générer 600 document) – Shuwaiee

9

Ne pas utiliser Office Automation. Office Automation ouvre une instance de bureau en arrière-plan et effectue les actions à ce sujet. Ouverture d'une instance de bureau 600 fois ne semble pas être une chose très intéressante à faire. (et il ne sera jamais exécuté côté serveur)

Jetez un coup d'œil à Open XML. Vous pouvez trouver des charges à ce sujet ci-dessous:

http://openxmldeveloper.org/

2

Paraît qu'il ya 2 questions ici:

  1. Comment foulez-vous hors du processus pour une id-valeur particulière

  2. Comment peupler le document.

sunilp a répondu Q2. Les contrôles de contenu liés aux données constituent le meilleur moyen d'injecter des données pour Word 2007 et les versions ultérieures.

Le focus de OP semble être Q1.

Il n'y a pas de commutateur de ligne de commande qui vous permet de passer une valeur arbitraire à la Parole: http://support.microsoft.com/kb/210565

Alors que je vois que vous avez 4 choix:

  1. faire tout le travail via le SDK OpenXML , ne jamais ouvrir Word du tout (comme d'autres affiches l'ont suggéré)

  2. créer un document préexistant minimal (contenant votre numéro d'identification) en utilisant OpenXML SDK, puis ouvrir le document

  3. automatiser Word pour passer le numéro d'identification du document, peut-être une propriété de document

  4. faire le travail pour créer les 600 documents dans Word en utilisant VSTO ou macros Word (VBA)

Me ? Je voudrais créer un docx contenant des contrôles de contenu lié aux données dans Word et l'enregistrer. Ensuite, j'y injecterais mes données en tant que partie xml personnalisée et je l'enregistrerais. (Cette étape que vous pourriez faire en utilisant le SDK OpenXML, ou dans Word si vous aviez besoin que Word mette à jour les liaisons pour vos processus en aval)

+0

Merci pour votre réponse, pourriez-vous s'il vous plaît élaborer un peu sur la dernière partie: "Puis, en y injectant mes données en tant que partie xml personnalisé, et enregistrez-le." Ce pourrait être le moyen de le faire. –

+0

Vous pouvez créer des contrôles de contenu dans Word et les lier ensemble avec un fichier XML. ce fichier xml sera également sauvegardé dans votre document Word. le remplacement du fichier xml modifierait les données affichées de votre document. Je recommande de jeter un oeil à la boîte à outils de contrôle de contenu de mot pour faire la liaison pour vous. – Jens

0

En ce qui concerne les réponses ci-dessus, je suis d'accord avec J. Vermeire que OpenXML est le chemin à parcourir. J'utilise depuis trois ans une boîte à outils basée sur OpenXML, qui produit des documents .docx, fusionnés à partir de modèles et de données de base de données. Il y a un exemple comment l'utiliser here. L'exemple montre comment travailler avec un document à la fois, pour travailler avec plusieurs d'entre eux, il suffit d'ajouter une boucle et d'appeler une méthode de génération de document.

+0

un lien mis à jour serait apprécié, on dirait que les données du lien ont été supprimées 7 mois après que vous avez posté ici – brw59

+0

L'article référencé a été supprimé le 10 Juillet 2015, et sa version récente est disponible dans le puissant WebArchive comme http: // web .archive.org/web/20150607050033/https: //www.codeproject.com/Articles/759408/Creating-Word-documents-in-Net-using-Docentric-Too. En tout cas, il s'agit de Docentric Toolkit, qui est une bibliothèque payante ... – AntonK

0

Ajouter des références pour Document.OpenXml.dll et 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 
     { 

     } 
    } 
Questions connexes