65.9K
CodeProject 正在变化。 阅读更多。
Home

您自己的 Word 书签编辑器

2018 年 4 月 15 日

CPOL

7分钟阅读

viewsIcon

12886

downloadIcon

514

用于 Word 报告易于处理的 Word 书签编辑器。

Sample Image - maximum width is 600 pixels

引言

很多人都面临着填写各种报告、时间表和其他各类文件的必要性。这些连续的报告通常只有一些细微的变化,只要文件格式不变,就不会带来太多麻烦。但当你的领导们又一次又一次地随意更改报告格式,而文档内容几乎不变时,就会带来巨大的麻烦。在这种情况下,拥有一个带有内容样本的文档模板,并将其应用于你富有远见的领导提供的任何新格式,可能会很有用。在本文中,我们提供了一个基于Word 书签的 Word 报告便捷处理的完整应用程序。

背景

演示项目WordMark是使用标准的Visual Studio C# Appwizard创建的。它是标准C#教程示例和一些CodeProject文章的集合:《使用 C# 自动处理 Word:以编程方式创建 Word 表格》by koolprasadd,《Word 自动化》by Prathapachandran等。与上述文章的示例不同,WordMark.exe不仅仅是一个演示:它是一个完整的应用程序,任何MS Word用户都可以使用。

在开始构建提供的项目之前,强烈建议您先看一下附带的演示文稿,以便对预期的输出有所了解。

演示说明

可执行文件WordMark.exe是使用MSVS-2015 pro C#构建的。

演示的最简单操作方法如下:

  • 调用菜单->文件->打开目标文件;在出现的FileDialog中,选择WeeklyReportBlank.doc
  • 调用菜单->文件->打开源文件;在出现的FileDialog中,选择WeeklyReportTable.doc
  • 调用菜单->编辑->将源文本应用于目标

报告文本将从WeeklyReportTable.doc跳转到WeeklyReportBlank.doc中相应的书签处,您可以将结果报告以任何名称保存在任何路径下。

按下“书签组合框”旁边的“BookMarks Combo”按钮,将出现“BookMarks”组合框,您可以浏览目标文档中的书签并选择文本

当您关闭应用程序并重新启动时,只需取消勾选“可见”复选框,调用相同的命令,然后调用菜单->文件->另存为目标文件并将结果报告保存在任何路径下,并命名为任何名称:如果文件和目标文件已完全准备好合并,则无需打开文档可见。不用说,目标文档都可以通过标准的Word在没有该应用程序的情况下单独准备。

一些菜单和一些特殊的控件处理按键,用于WordMark 应用程序的正确操作

菜单->文件

  • 打开目标文件:打开文档文件,用于填充书签文本(前提是文档中已准备好书签
  • 另存为目标文件:将目标文件保存在指定的路径和名称下
  • 关闭目标文件:如果文件已更改,会提示保存后关闭
  • 打开源文件:打开带有书签标签文本单元格表的文档文件(前提是表格已准备好)
  • 另存为源文件:将源文件保存在指定的路径和名称下
  • 关闭源文件:如果文件已更改,会提示保存后关闭
  • 退出:关闭应用程序,如果文件已更改,会提示保存后退出

菜单->编辑

  • 新建书签:调用“书签名称”对话框,如果点击确定,则在目标文档中出现具有输入名称的新书签
  • 删除书签组合框:从目标文档中删除组合框中指定的书签
  • 清除书签文本:清除文档中选定的书签目标文档中的文本;如果没有选择,则清除所有文本
  • 清除书签:从目标文档中移除文档中选定的书签;如果没有选择,则移除所有书签
  • 创建书签表:在文档中创建带有书签文本单元格表格(如果尚未打开,则创建)
  • 将源文本应用于目标:将源表格中的文本字体应用到目标文档中相应的书签处 

 菜单->帮助

  • WordMark 帮助:显示带有当前帮助文本帮助对话框
  • 关于 WordMark:应用程序版权和许可信息

 控件

  • “可见”复选框:如果目标文件已完全准备好合并,则无需打开文档可见
  • “书签组合框”按钮:使“书签”组合框可见
  • “书签”组合框:浏览目标文档中的书签并选择文本
  • “书签排序->按顺序”单选按钮:按目标文档中的顺序对组合框中的书签进行排序
  • “书签排序->按名称”单选按钮:按字母顺序对组合框中的书签进行排序
  • “表格行排序->按顺序”单选按钮:按目标文档中的顺序对文档表格中的书签标签进行排序 
  •  
  • “表格行排序->按名称”单选按钮:按字母顺序对文档表格中的书签标签进行排序 
重要说明
  • 一旦文档通过WordMark应用程序打开,就必须通过该应用程序关闭。否则,WordMark应用程序可能会出现问题。
  • 如果您在“书签”组合框可见的情况下,使用标准的Word目标文档中的书签进行了一些更改,只需按“书签组合框”按钮进行同步。
  • 如果您在目标文档的某个表格中有选定区域,然后选择菜单->编辑->新建书签,并在“书签名称”对话框中选择确定,则为每个选定的单元格创建新的书签,该书签名称与表格选定区域左上角的行-列索引一致,并从目标文档的表格选定区域开始。

构建说明

提供的项目是使用MSVS-2015 pro C#Windows 10Windows 7上开发的。

从一台计算机迁移到另一台计算机时可能遇到的唯一问题是对Microsoft.Office.Interop.Word的引用安装。

如果在编译过程中出现OfficeWord未访问的错误消息,只需在解决方案资源管理器->WordMark上右键单击并安装即可。

代码解释

所有以下的菜单控件处理命令都是使用标准的MSVS C# AppWizard技术完成的。因此,我认为没有什么比标准教程解释得更清楚的了。我只想提几点我没有在教程中找到,而是通过反复试验自己发现的。

在这里,我必须承认这是我第一次接触 C#。因此,我的一些论断对于老练的人来说可能显得很奇怪。我很乐意阅读任何评论和建议。

1. 表格单元格中的文本

表格单元格中的文本以两个字节结尾:'\13' 和 '\7'。即使单元格看起来是空的,这两个字节也存在。因此,如果从表格的单元格借用的文本必须在两个字节处截断

     private bool ApplyTextAtBookmarkFromRow(int iRow)
        {
            Word.Table TableSrc = (Word.Table)docSrc.Tables[1]; //Select Table of Source Doc          
             string strB = TableSrc.Cell(iRow, 1).Range.Text;   //Name of the Bookmark in row specified
            strB = strB.Substring(0, strB.Length - 2);          //Name cut with two bytes
            string strT = TableSrc.Cell(iRow, 2).Range.Text;    //Text of the Bookmark in row specified
            strT = strT.Substring(0, strT.Length - 2);          //Text cut with two bytes
            //Pick up the Font of the Cell:
            Microsoft.Office.Interop.Word.Font fontSrc = TableSrc.Cell(iRow, 2).Range.Font;
            Word.Bookmark bmk = docTgt.Bookmarks[strB];         //Select Bookmark in Target doc
        if( ApplyTextAtBookmark(bmk, strT, fontSrc) == false)   //Replace the text in the BookMark
                return false;
             return true;
        }

此外,拥有一个函数来识别文本是否属于某个表格的单元格也很有用

      private bool IsTextOfTable( string strN)
        {
            if (strN.Length < 2)    //If Text in Cell at least 2 bites present
                return false;
           string strA = strN.Substring(strN.Length - 2);//2 last symbols borrowed
           byte[] bytes = Encoding.ASCII.GetBytes(strA); //convert to bites
           return bytes[0] == 13 && bytes[1] == 7;       //true if bites 13 & 7  
        }

以及一个函数来识别  书签是否属于某个表格的单元格

          private bool IsBookMarkOfTable( Word.Bookmark bmk)
        {
            bool bTable = false;
            try
            {
                bTable = bmk.Range.Cells.Count > 0;
            }
            catch
            {
                bTable = false;
            }
            return bTable;
        }

2. 书签文本替换

在指定的书签处进行文本替换过程在WordMark项目中也有一些细节

      private bool ApplyTextAtBookmark(Word.Bookmark bmk, string strSrc, Microsoft.Office.Interop.Word.Font fontSrc)
        {
            if (bmk == null)          //if no Bookmark - nothing to do
                return false;
     
            bool bTable = IsBookMarkOfTable(bmk); //Flag of Bookmark in the Table's Cell
            int nSrc = strSrc.Length; //Length of the Source Text
            string strTgt = "";       //Text at the Bookmark
            if (bmk.Range.Text != null)
                strTgt = bmk.Range.Text; //Text at the Bookmark

            if (nSrc == 0)
            {
                strSrc = " ";            //if Source Text empty assum as white space
                nSrc = strSrc.Length;
            }
            string strB = bmk.Name;      //Remember the name of the Bookmark
            if (bmk.Range.Text == null)  //if Bookmark Text not exist assum as white space
                bmk.Range.Text = " ";

            int nTgt = bmk.Range.Text.Length; //Length of the Bookmark Text
            int nDif = nSrc - nTgt;  //Difference between Source and Bookmark Text length
            if (!bTable)              //if Bookmark not in Table
                if (nDif < 0)            //if Source Text shorter then BookMarks one 
                    for (int k = 0; k < -nDif; k++)
                        strSrc += " ";   //append white space until equal  
            nSrc = strSrc.Length;    //Length of the Source Text 
            object bgnA = bmk.Start;        //Range Start
            object finA = bmk.Start + nSrc; //Range End
            bmk.Range.Text = strSrc;        //Replace the Text in BookMark
            Word.Range rgA = docTgt.Range(ref bgnA, ref finA);//new Range fixed
            rgA.Select();               //Select new Range
            rgA.Font = fontSrc;         //Apply Font to Range 
            object rng = appWord.Selection.Range;  //Select new Range
            //new Bookmark with the same Name fixed:
            Word.Bookmark bkmr = docTgt.Bookmarks.Add(strB, ref rng);
            if (bTable == false)      //if Bookmark not in Table
                if (nDif > 0)         //if New Text is longer then the old one 
                {
                    object bgn = bkmr.Range.Start + nSrc + 1;       //go to end of new Text
                    object fin = bkmr.Range.Start + nSrc + nDif + 1;//go to end + difference
                    Word.Range rg = docTgt.Range(ref bgn, ref fin);//fix range from end to diffence len
                    string strf = rg.Text;   //Pick up text from difference Range
                    int nBreak = strf.IndexOf("\n");    //End of line
                    if (nBreak > 0)
                    {
                        strf = strf.Substring(0, nBreak - 1);
                      
                        while (strf.Substring(0, 1) == " " || strf.Substring(0, 1) == "_"
                         &&  strf.Length > 1)
                        {
                            strf = strf.Substring(1);//while first simbol is empty cut first simbol
                        }
                        rg.Text = strf;  //apply the text cut at the end of new Text
                    }
                }
            return true;
        }

请注意,所有这些关于旧文本和新文本长度差异的调整都是为了保持文本和环境的位置不变(你的领导认为保持他们明智的文档格式不变是绝对必要的)。

3. 表格中的多个书签初始化

作者还开发了在表格中进行多个书签初始化的功能,这可能对开发人员有益

        private void MenuNewBookMark_Click(object sender, EventArgs e)
        {
            if (w.ShowDialog() == DialogResult.OK)        //new Bookmark Name Ok   
            {
                int nCel = 0;                             //Number of Cells selected
                if (appWord.Selection.Tables.Count > 0)   
                    nCel = appWord.Selection.Cells.Count; //Number of Cells selected

                if (nCel < 2) //if no Cells or Single Cell just append new BookMark
                    docTgt.Bookmarks.Add(w.textBox1.Text, appWord.Selection.Range);
                else
                {
                    Word.Table tbl = appWord.Selection.Tables[1];   //Table selected
                    //TopLeft corner of Selection Row index:
                    int rowStart = appWord.Selection.Cells[1].Row.Index;
                    //TopLeft corner of Selection Column index:
                    int colStart = appWord.Selection.Cells[1].Column.Index;
                    //RightBottom corner of Selection Row index:
                    int rowFin = appWord.Selection.Cells[appWord.Selection.Cells.Count].Row.Index;
                    //RightBottom corner of Selection Column index:
                    int colFin = appWord.Selection.Cells[appWord.Selection.Cells.Count].Column.Index;

                    for (int i = rowStart; i <= rowFin; i++)      //for each row selected
                        for (int j = colStart; j <= colFin; j++)  //for each column selected
                        {
                            tbl.Cell(i, j).Range.Select();       //Select Range of the cell
                            int ri = i - rowStart + 1;            //row index
                            int ci = j - colStart + 1;            //column  index     
                            //Append new Bookmark indexed:    
                            docTgt.Bookmarks.Add(w.textBox1.Text + "_" + 
                                                 ri.ToString("00") + "_" + ci.ToString("00"));
                        }
                }
                if (comboBox1.Visible)                      //if 'BookMarks' Combo Box is visible
                {
                    button1_Click(sender, e);               //synchronize Combo Box Content
                    int index = comboBox1.FindString(w.textBox1.Text); //index of Name typed 
                                                                       //in Dialog Box
                    comboBox1.SelectedIndex = index;        //select item with the Name typed 
                                                            //in Dialog Box
                }
            }
        }

应用程序处理和使用提供的项目进行您自己的应用程序开发

WordMark.exe应用程序对于任何稍微熟悉Word 书签的用户来说都易于操作。不需要任何编程技能。

您可以获取整个项目,重命名它,并随意组合和改进代码。

或者,您可以获取其中包含的任何过程文件,并通过菜单项目->现有项将其插入到任何您自己的 C# 项目中。

如果您引用了我的代码,将不胜感激。

关注点

我相信这个应用程序和代码对于处理文档的软件人员应该有所帮助。

其想法是开发一套程序,用于处理你上司提供的WordExcel文档表格,以完成大量文书工作。

我相信,通过安排让计算机能够打出海量文件,让高层人士满意是可能的。

历史

故事才刚刚开始。

© . All rights reserved.