使用C#从ObservableCollection创建Word文件 [英] Creating Word file from ObservableCollection with C#

查看:87
本文介绍了使用C#从ObservableCollection创建Word文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有2个字符串属性的类的可观察集合:Word和Translation.我想创建以下格式的Word文件:


单词 =翻译

单词 =翻译单词 =翻译...


单词文档必须在两列(PageLayout)中,单词应以粗体显示.

我首先尝试过Microsoft.Office.Interop.Word. PageSetup.TextColumns.SetCount(2)设置PageLayout.至于文本本身,我使用了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(或可能结合使用)?有人可以告诉我如何正确编写此代码,这样如果集合相对较大,就不会花很长时间吗?任何帮助表示赞赏. :)

解决方案

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

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

您的Word模板如下所示:

如果您具有 pseudo 代码可以帮助您入门. rel ="nofollow noreferrer">已安装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();
    }

I have an observable collection with a class that has 2 string properties: Word and Translation. I want to create a word file in format:


word = translation word = translation

word = translation word = translation...


The word document needs to be in 2 Columns (PageLayout) and the Word should be in bold.

I have first tried Microsoft.Office.Interop.Word. PageSetup.TextColumns.SetCount(2) sets the PageLayout. As for the text itself I used a foreach loop and in each iteration I did this:

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

This does exactly what I want, but if there are 1000 items in the collection it takes about 10sec, much much more if the number is 10k+. I then used a StringBuilder and just set document.Content.Text = sb.ToString(); and that takes less than a sec, but I can't set the word to be bold that way.

Then I switched to using Open XML SDK 2.5, but even after reading the msdn documentation I still have no idea how to make just a part of the text bold, and I don't know if it's even possible to set PageLayout Columns count. The only thing I could do was to make it look the same as with Interop.Word, but with just 1 column and <1sec creation time.

Should I be using Interop.Word or Open XML (or maybe combined) for this? And can someone pls show me how to write this properly, so it doesn't take forever if the collection is relatively large? Any help is appreciated. :)

解决方案

OOXML can be intimidating at first. http://officeopenxml.com/anatomyofOOXML.php has some good examples. Whenever you get confused unzip the docx and browse the contents to see how it's done.

The basic idea is you'd open Word, create a template with the styling you want and a code word to find the paragraph, then multiply the paragraph, replacing the text in that template with each word.

Your Word template would look like this:

Here's some pseudo code to get you started, assuming you have the SDK installed

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

这篇关于使用C#从ObservableCollection创建Word文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆