使用 C# 从 ObservableCollection 创建 Word 文件

Creating Word file from ObservableCollection with C#

我有一个带有 class 的可观察集合,它具有 2 个字符串属性:Word 和 Translation。我想创建一个格式为:

的 word 文件

word = 翻译 word = 翻译

word = 翻译 word = 翻译...


Word 文档需要分两栏(PageLayout)并且 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 列数。我唯一能做的就是让它看起来与 Interop.Word 相同,但只有 1 列和 <1 秒的创建时间。

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

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

中重新创建它

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();
    }

打开 XML 是比 Office COM 更好的选择。但问题是它是一个低级文件格式库,不像 Office COM 不能在高抽象级别上工作。你可能想走那条路,但我建议你首先考虑研究一个商业图书馆,它会给你带来高级 DOM 的好处,而无需在生产机器上安装 MS Word。我们公司最近购买了 this toolkit,它允许您使用基于模板的方法以及 DOM/programmatic 方法来处理 generate/modify/create 文档。