简体   繁体   English

Word VSTO 加载项:通过其范围更改段落的文本

[英]Word VSTO Add-In : Changing the Text of a Paragraph through its Range

I'm programming an add-in which uses a GroupContentControl (GCC) to write-protect each paragraph that uses the "Heading 1" style.我正在编写一个加载项,它使用 GroupContentControl (GCC) 来写保护使用“标题 1”样式的每个段落。 Once protected, those headings can only be changed through the add-in.一旦受到保护,这些标题只能通过加载项进行更改。 To that end, I wrote a simple method that removes the paragraph's GCC, assigns a new value to the paragraph's Range.Text property, sets the style to Heading 1 again, and then sets a new GCC to protect the paragraph.为此,我编写了一个简单的方法,删除段落的 GCC,为段落的 Range.Text 属性分配一个新值,再次将样式设置为 Heading 1,然后设置一个新的 GCC 来保护该段落。

I'm still new to Office programming, and my assumption was that the Range object could be used throughout the whole process.我还是 Office 编程的新手,我的假设是 Range 对象可以在整个过程中使用。 However, the method misbehaves : it inserts a carriage return after the new paragraph text, and then takes the next paragraph in the document and makes it a Heading 1 paragraph, then write-protects it.但是,该方法行为不端:它在新段落文本后插入回车符,然后将文档中的下一段设为标题 1 段落,然后对其进行写保护。

Here's my method, along with calls to a logging function to see how the Range evolves :这是我的方法,以及对日志函数的调用以查看范围如何演变:

void ChangeParagraphText (Word.Paragraph p, string NewText)
{
    Log("Range 1 : " + p.Range.Start + " - " + p.Range.End);
    UnlockTitle(p);     // remove the paragraph's GroupContentControl     
    Log("Range 2 : " + p.Range.Start + " - " + p.Range.End);
    p.Range.Text = NewText;   // change the paragraph's text
    Log("Range 3 : " + p.Range.Start + " - " + p.Range.End);
    p.Range.set_Style(Globals.ThisAddIn.Application.ActiveDocument.Styles[Word.WdBuiltinStyle.wdStyleHeading1]);
    Log("Range 4 : " + p.Range.Start + " - " + p.Range.End);
    LockTitle(p);       // write-protect the paragraph with a GroupContentControl
    Log("Range 5 : " + p.Range.Start + " - " + p.Range.End);
}

Once it has run, here are the contents of the log file :运行后,以下是日志文件的内容:

Range 1 : 90 - 99
Range 2 : 90 - 97
Range 3 : 100 - 102
Range 4 : 100 - 102
Range 5 : 100 - 104

This taught me some interesting things.这教会了我一些有趣的事情。 For starters, the length of the Range decreases by two after removing the GCC, and increases by two when adding a GCC.对于初学者来说,去掉GCC后Range的长度减少2,增加GCC时增加2。 The important part, though, is the third log entry : it shows that as soon as I assign the paragraph's Range.Text, the Range changes completely.然而,重要的部分是第三个日志条目:它表明,一旦我分配了段落的 Range.Text,范围就完全改变了。 The values match the next paragraph in my test document.这些值与我的测试文档中的一段相匹配。

Reading the Range.Text property also shows that it ends with a line feed character (ASCII 13).读取 Range.Text 属性还显示它以换行符 (ASCII 13) 结尾。 If I omit it, I end up with the next paragraph appended to my Heading 1 paragraph.如果我省略它,我最终会将下一段附加到我的标题 1 段落。 If I put it in, I end up with the second paragraph being treated as the Heading 1 paragraph.如果我把它放进去,我最终会将第二段视为标题 1 段。 None of those behaviors works for me.这些行为都不适合我。

My question is : how do I programmatically change the text of a paragraph ?我的问题是:如何以编程方式更改段落的文本? I assume it has to be possible, but if it's not, what's the workaround ?我认为它必须是可能的,但如果不是,有什么解决方法? I've been thinking of creating a new paragraph after the one I want to change, and then deleting the old one, but that seems inelegant.我一直想在我想更改的段落之后创建一个新段落,然后删除旧段落,但这似乎不雅。

First, quick answer to your stated question: how to replace the text of the paragraph while leaving the paragraph, itself, intact.首先,快速回答您提出的问题:如何在保持段落本身完整的同时替换段落的文本。 I'm not able to use the code you provide as it doesn't show how you derive p .我无法使用您提供的代码,因为它没有显示您如何导出p So I'm taking an arbitrary Paragraph object:所以我正在使用一个任意的Paragraph对象:

Word.Range rngPara = doc.Paragraphs[1].Range;
object unitCharacter = Word.WdUnits.wdCharacter;
object backOne = -1;
rngPara.MoveEnd(ref unitCharacter, ref backOne);
rngPara.Text = "replacement text";

Background information :背景资料

The most important aspect of your problem is understanding Word Range objects.问题最重要的方面是理解 Word Range对象。

First, never rely on the Start and End properties for identifying a Range.首先,永远不要依赖StartEnd属性来识别范围。 They're OK for "snapshots", or dynamically setting one Range's Start or End point to that of a second.它们适用于“快照”,或者将一个范围的起点或终点动态设置为一秒的起点或终点。 But as soon as any editing whatsoever takes place in a document, you can throw them away.但是,只要在文档中进行了任何编辑,您就可以将它们扔掉。

When you need to work with Ranges, use Range objects (variables) for the duration of the running code.当您需要使用 Ranges 时,请在运行代码期间使用Range对象(变量)。

Yes, as you analyze, Paragraph.Range.Text does include the end-of-paragraph mark.是的,在您分析时, Paragraph.Range.Text确实包含Paragraph.Range.Text结束标记。 This is ANSI 13 and is not just a carriage return;这是 ANSI 13,不仅仅是一个回车; under the covers it stores a load of information about the paragraph formatting.在幕后,它存储了有关段落格式的大量信息。 When you want to work with only the text, shorten the Range back by one character to leave the paragraph mark out of the Range.如果您只想处理文本,请将范围缩短一个字符以将段落标记保留在范围之外。 This can be done using the MoveEnd method.这可以使用MoveEnd方法来完成。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM