【问题标题】:Creating Word file from ObservableCollection with C#使用 C# 从 ObservableCollection 创建 Word 文件
【发布时间】:2016-01-04 19:04:23
【问题描述】:

我有一个可观察的集合,其中包含一个具有 2 个字符串属性的类:Word 和 Translation。我想创建一个word文件格式:


word = 翻译 word = 翻译

word = 翻译 word = 翻译...


word文档需要2列(页面布局),Word应该是粗体。

我首先尝试了 Microsoft.Office.Interop.Word。 PageSetup.TextColumns.SetCount(2) 设置页面布局。至于文本本身,我使用了一个 foreach 循环,并且在每次迭代中我都这样做了:

paragraph.Range.Text = Word + " = " + Translation;
object boldStart = paragraph.Range.Start;
object boldEnd = paragraph.Range.Start + Word.Length;
Word.Range boldPart = document.Range(boldStart, boldEnd);
boldPart.Bold = 1;

paragraph.Range.InsertParagraphAfter();

这正是我想要的,但如果集合中有 1000 个项目,则大约需要 10 秒,如果数字是 10k+ 则更多。然后我使用了 StringBuilder 并设置了document.Content.Text = sb.ToString();,这需要不到一秒的时间,但我不能这样设置单词为粗体。

然后我切换到使用 Open XML SDK 2.5,但即使在阅读了 msdn 文档之后,我仍然不知道如何将部分文本设置为粗体,甚至不知道是否可以设置 PageLayout Columns数数。我唯一能做的就是让它看起来与 Interop.Word 相同,但只有 1 列和

我应该为此使用 Interop.Word 还是 Open XML(或者可能结合使用)?有人可以告诉我如何正确地写这个,所以如果集合相对较大,它不会永远花费?任何帮助表示赞赏。 :)

【问题讨论】:

  • 尽可能避免互操作(在你的情况下是可能的)
  • 您可以下载 Open XML SDK 生产力工具here。您可以使用它来查看制作 word 文档时生成的 xml 代码,它还显示了您需要生成它的 c# 代码
  • @AlexanderDerck 我下载了生产力工具,但还没有安装。看到您的评论后,我安装了它,制作了一个测试 word 文档,在工具中花费了大约 1-2 分钟,找到了我需要知道的内容并在 VS 中编写了代码......我之前花了 5 个多小时阅读/学习互操作和开放 XML SDK 并尝试对其进行编码。当我下载它时,我对这个工具的概念有错误的想法。感谢您提供简单但很好的建议:D
  • @VincentProxy 是的,open xml sdk 的文档很糟糕,但至少那个工具很棒:)

标签: c# ms-word openxml observablecollection


【解决方案1】:

OOXML 起初可能令人生畏。 http://officeopenxml.com/anatomyofOOXML.php 有一些很好的例子。每当您感到困惑时,解压缩 docx 并浏览内容以查看其完成方式。

基本思路是打开 Word,创建一个具有所需样式的模板和一个代码字来查找段落,然后将段落相乘,用每个单词替换该模板中的文本。

您的 Word 模板如下所示:

这里有一些代码让你开始,假设你安装了SDK

    var templateRegex = new Regex("\\[templateForWords\\]");
    var wordPlacementRegex = new Regex("\\[word\\]");
    var translationPlacementRegex = new Regex("\\[translation]\\]");

    using (var document = WordprocessingDocument.Open(stream, true))
    { 
      MainDocumentPart mainPart = document.MainDocumentPart;

      // do your work here...
      var paragraphTemplate = mainPart.Document.Body
       .Descendants<Paragraph>()
       .Where(p=>templateRegex.IsMatch(p.InnerText)); //pseudo 
       //... or whatever gives you the text of the Para, I don't have the SDK right now

      foreach (string word in YourDictionary){
        var paraClone = paragraphTemplate.Clone(); // pseudo 

// you may need to do something like 
// paraClone.Descendents<Text>().Where(t=>regex.IsMatch(t.Value))
// to find the exact element containing template text
        paraClone.Text = templateRegex.Replace(paraClone.Text,"");// pseudo 
        paraClone.Text = wordPlacementRegex.Replace(paraClone.Text,word);
        paraClone.Text = translationPlacementRegex.Replace(paraClone.Text,YourDictionary[word]);

        paragraphTemplate.Parent.InsertAfter(paraClone,ParagraphTemplate); // pseudo
      }

      paragraphTemplate.Remove();

      // document should auto-save 
      document.Package.Flush();
    }

【讨论】:

  • 我在看到我的问题的前 2 个 cmets 后立即编写了代码,但感谢您的回答,我认为它最有帮助。我需要练习一下并再次阅读一些 msdn 文档。我不确定您为什么要查看后代,尽管我记得在 msdn 示例中看到过。我真的很喜欢使用正则表达式的想法,因为我喜欢正则表达式 :D,我可能会将它合并到我的代码中。
  • 生产力工具需要权衡取舍,它可能适用于您,也可能不适用于您。如果您正在生成供人类阅读的文件,您可以确定他们会希望随着时间的推移添加/删除/更改内容,这变得很难用生成的代码处理,模板方法可以轻松更改输出而无需代码的更改。当然,如果您的文档只是一个自动化步骤,那么生成的代码是更好的选择,因为无论出于何种原因,它都不太可能不工作。
  • ...根据您对精确布局和字体粗细的需要判断(粗体 正常)我认为输出将被人类使用
  • 通过模板方法,您的意思是我是否需要先读取文件并获取可能是新的模板,然后更改文件并将其返回给用户?在我的应用程序中,如果用户想要打印字典,或者只是将其作为可以在 MS Word 中读取和/或更改的文件,用户可以制作一个 word 文件。创建文件后,应用程序不会再次重复使用它,也不关心任何新模板。我有一个序列化文件,作为二进制保存文件,由应用程序本身使用。
  • 你能帮我做一件事吗?每当有新字母开始时,我都会在该字母之前添加两次new Break(),并在其之后添加两次。因此,右列可以以 1 或 2 个空行开头。有没有办法让我设定一个条件,在这个条件下我将在该字母之后添加中断,或者有一种方法来格式化列本身,使其不以空行开头?
【解决方案2】:

OpenXML 绝对更好,因为它更快、错误更少、运行时更可靠、更灵活(尤其是在服务器环境中)。找出如何使用 OpenXML 制作一个或另一个元素并不难。由于 docx 文件只是一个包含 xml 文件的 zip 文件,因此我打开它并阅读 xml 以了解单词本身是如何产生的。首先,我创建一个文档,然后对其进行格式化(在您的情况下,您可以创建一些包含两列和粗体字的文件),保存它,将其重命名为 .zip 文件。然后打开它,打开里面的“word”目录和目录里面的文件“document.xml”。该文档包含 xml 的基本部分,看这个不难弄清楚如何在 OpenXML 中重新创建它

【讨论】:

  • 误导。 OOXML 有一个 SDK,它比结合 XML 和 ZIP SDK 更容易使用,可验证结构并支持强类型 Linq
  • @StenPetrov 我对使用 xml 或 zip sdk 只字未提,我的回答是关于使用 OpenXML,而实际上,您的回答与我的大部分内容重复。
  • 您的答案中唯一相关的信息是 docx 是一个 zip,其余的“不难”
  • @StenPetrov 在答案中,我解释了如何找到 OpenXml OP 想要构建的理想结构。根据他的问题,我假设他知道这个库的基本知识,所以我不需要向他解释 WordprocessingDocument.Open 和其他内容。我没有提到任何关于使用纯 xml 或 zip 库的内容,我不明白你从哪里得到它。 “每当你感到困惑时,解压缩 docx 并浏览内容以查看它是如何完成的。” - 就是我所说的,而且非常相关。仅仅阅读文档,你永远不会得到正确的结构。
  • @StenPetrov 我在里面玩过一些 .zip 和 xml 文件。内容看起来很有趣,我可能会将它与生产力工具一起使用
【解决方案3】:

Open XML 是比 Office COM 更好的选择。但问题是它是一个低级文件格式库,与 Office COM 不同,它不能在高抽象级别上工作。您可能想走这条路,但我建议您首先考虑研究一个商业库,该库将为您提供高级 DOM 的好处,而无需在生产机器上安装 MS Word。我们公司最近购买了this toolkit,它允许您使用基于模板的方法以及 DOM/编程方法来生成/修改/创建文档。

【讨论】:

  • 这个工具包是否允许您按照问题中的要求将部分文本加粗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-13
  • 1970-01-01
  • 1970-01-01
  • 2019-12-26
  • 1970-01-01
相关资源
最近更新 更多