私は複数ページの文書を持っています。私の目的は、'19 -x 'のようなページ番号の形式をカスタマイズすることです.xは1,2,5 、等。実際には、単語のページフィールドは私が望むものではありません。私はテキストを挿入することができますそこに だから私のソリューションは、図形を描画することですが、「19」かさえ'19が好き-1' 、オープンXMLで、各ページの最初の段落に:私が欲しいもの複数ページのms文書の段落のポイントを取得
<w:pict>
<v:shapetype id="_x0000_t202" coordsize="21600,21600" o:spt="202" path="m,l,21600r21600,l21600,xe">
<v:stroke joinstyle="miter" />
<v:path gradientshapeok="t" o:connecttype="rect" />
</v:shapetype>
<v:shape id="_x0000_s2050" type="#_x0000_t202" style="position:absolute;left:0;text-align:left;margin-left:-1in;margin-top:708pt;width:39.75pt;height:12.75pt;z-index:251658240;v-text-anchor:middle" filled="f">
<v:textbox inset="0,0,0,0">
<w:txbxContent>
<w:p w:rsidR="00172BF9" w:rsidRDefault="00172BF9" w:rsidP="00172BF9">
<w:r>
<w:rPr>
<w:rFonts w:hint="eastAsia" />
</w:rPr>
<w:t>19-1</w:t>
</w:r>
</w:p>
</w:txbxContent>
</v:textbox>
</v:shape>
</w:pict>
するには余白トッププロパティのスタイルの属性を<v:shape/>
要素に設定することです。今では、私はフッターの位置を持っている、ちょうどfieldParaRangeTopそれを呼び出す:
HeaderFooter footer = currentDocument.Sections[1].Footers[WdHeaderFooterIndex.wdHeaderFooterPrimary];
Range footerRange = footer.Range;
int left,top,width,height ;// px
currentDocument.ActiveWindow.GetPoint(out left,out top,out width,out height,footerRange);
float fieldParaRangeTop = top * 3/4;// pt
は今、私は、各ページの最初の段落の位置を取得する必要があるので、私は減算するfieldParaRangeTopを使用することができますそれ:
Paragraph fistParaEachPage = ...;// first para of each page;
int top;
currentDocument.ActiveWindow.GetPoint(out left,out top,out width,out height,fistParaEachPage.Range);
float fpTop = top * 3/4;
マージントップの値は次のとおりです。
value = fieldParaRangeTop - fpTop;
これは、新しいページ番号が各ページの最初の段落に相対的に表示される場所です。 fpTop = 178pt:fpTop = 104ptが、2番目のページに:
結果は、最初のページの最初の段落の位置があります。
私の質問はなぜ方法currentDocument.ActiveWindow.GetPoint(out left,out top,out width,out height,paragraph.Range)
出力してもよい異なるトップ値、両者がそれぞれのページの最初の段落は、最初のページでの段落目と2ページ目にある段落で、ですか?どのようにして正しい値を得ることができますか?
ありがとうございます!
コード例:実際に
public class Example
{
public void TestLocation(){
object missingObj = Type.Missing;
object boolFalse = false;
object boolValue = true;
Application application = null;
Document currentDocument = null;
try{
application = new Application();
application.Visible = false;
object path =System.IO.Path.Combine(System.Windows.Forms.Application.StartupPath, "test.docx");
// open an *.docx with several pages
currentDocument = application.Documents.Open(ref path,ref boolFalse,ref boolValue,ref boolFalse,
ref missingObj,ref missingObj,ref boolFalse,
ref missingObj,ref missingObj,ref missingObj,ref missingObj,ref boolValue,
ref missingObj, ref missingObj,ref boolFalse,ref missingObj);
// just consider the first section
Section currentSection = currentDocument.Sections[1];
HeadersFooters footers = currentSection.Footers;
// insert a page field in the footer,
// so i can get it's position to locate our new page
// number - a shape that will cover the page field - with the format of '19' or '19-1'
Field f = GetFieldInFooter(currentSection.Footers);
if(f == null){
Console.WriteLine("The page field has not been setted yet!");
return ;
}
// the location of the page field in the word
Location point = GetPositionOfRange(currentDocument,f.Result);
float fieldParaRangeTop = point.Y ;// in pt
float fieldLeft = point.X ;// in pt
// the first paragraph in the document, and is also the first paragraph in the first page
Range firstParaRange = currentSection.Range.Paragraphs[1].Range;
point = GetPositionOfRange(currentDocument,firstParaRange);
float firstParaTop = point.Y ;// in pt
float firstParaLeft = point.X ;// in pt
//
// in the following code, i will get the first paragraph of each page in a for-loop,
// and caculate their positions.
//
object unit = WdUnits.wdParagraph;
object count = 1;
StringBuilder text = new StringBuilder();
string format = "location of the page number in page {0} is ({1},{2})";
// the value is the one that would be set to the margin-top property of the style attribute in <v:shape/> element.
float value = fieldParaRangeTop - firstParaTop;
text.AppendLine(string.Format(format,1,(fieldLeft - firstParaLeft),value));
int pageNumber = 1;
Console.WriteLine(">>>Count of paragraphs in this section: "+currentSection.Range.Paragraphs.Count);
for(int i = 2;i<= currentSection.Range.Paragraphs.Count;i++){
Paragraph para = currentSection.Range.Paragraphs[i];
if(this.IsRangeOfPage(para.Range,pageNumber))
continue;
pageNumber++;
if(!this.IsRangeInTheSamePage(para.Range)){
// if para is across two pages,
// then get it's next sibling as the first paragraph in this page
para = currentSection.Range.Paragraphs[i+1];
}
object start = true;
currentDocument.ActiveWindow.ScrollIntoView(para.Range,start);
point = GetPositionOfRange(currentDocument,para.Range);
value = fieldParaRangeTop - point.Y;
Console.WriteLine(string.Format(">>>the first paragraph of page {0} is \r\n{1}",pageNumber,para.Range.Text));
text.AppendLine(string.Format(format,pageNumber,(fieldLeft - point.X),value));
}
Console.WriteLine(text.ToString());
// other codes here for building an <w:pict/> element with the positions using OpenXMl dll
} catch(Exception ee){
Console.WriteLine(":::ERROR::::::"+ee.Message);
}
finally{
if(application != null){
currentDocument.Close();
currentDocument = null;
application.Quit();
application = null;
}
}
}
private Field GetFieldInFooter(HeadersFooters footers){
if(footers == null || footers.Count == 0)
{
Console.WriteLine("There is no footer in current section.");
return null;
}
Field f = null;
foreach(HeaderFooter footer in footers){
Range footerRange = footer.Range;
if(footerRange.Fields.Count == 0)
continue;
foreach(Field field in footerRange.Fields){
if(field.Type == WdFieldType.wdFieldPage)
{
f = field;
break;
}
}
if(f != null)
break;
}
return f;
}
private Location GetPositionOfRange(Document currentDocument,Range range){
int left = 0;
int top = 0;
int width = 0;
int height = 0;
currentDocument.ActiveWindow.GetPoint(out left,out top,out width,out height,range);
return new Location(left * 3/ 4,top* 3/ 4,width* 3/ 4,height* 3/ 4);
}
/// <summary>
/// Determines if the range is in the page <code>currentPage</code>
/// </summary>
/// <param name="range"></param>
/// <param name="currentPage"></param>
/// <returns></returns>
private bool IsRangeOfPage(Range range,int currentPage){
object s = range.Start,e = range.End;
try{
Range sr = range.Document.Range(ref s,ref s);
Range se = range.Document.Range(ref e,ref e);
int page1 = (int)sr.Information[WdInformation.wdActiveEndPageNumber];
int page2 = (int)se.Information[WdInformation.wdActiveEndPageNumber];
if(page1 == page2 && page1 == currentPage)
return true;
return false;
}catch(Exception){return true;}
}
/// <summary>
/// Determines whether the <code>range</code> is in the same page, that is both the <code>Start</code> and <code>End</code> of this range
/// is in the same page. Or this range will across two pages.
/// </summary>
/// <param name="range"></param>
/// <returns></returns>
private bool IsRangeInTheSamePage(Range range){
object s = range.Start,e = range.End;
Range sr = range.Document.Range(ref s,ref s);
Range er = range.Document.Range(ref e,ref e);
int page1 = (int)sr.Information[WdInformation.wdActiveEndPageNumber];
int page2 = (int)er.Information[WdInformation.wdActiveEndPageNumber];
if(page1 == page2)
return true;
return false;
}
}
public class Location{
public Location(float x,float y,float width, float height){
this.X = x;
this.Y = y;
this.Width = width;
this.Height = height;
}
public float X;
public float Y;
public float Width;
public float Height;
public override string ToString()
{
return string.Format("[Location X={0}, Y={1}, Width={2}, Height={3}]", X, Y, Width, Height);
}
}
希望の結果を示す例(例:スクリーンショット)を提供できますか? –
お返事ありがとうございました!私はすでに複数のページを持つ文書という単語を除いて私の例を追加しました。あなたは新しいものを作ることができます。 – qpong
あなたは間違った方向に向かっているようです。これは、Wordが提供する適切な書式設定オプションを使用することで解決される可能性が非常に高いです。位置を自分で計算する必要はありません。スクリーンショットやサンプルドキュメントを提供した場合、あなたの形状をどのようにフォーマットする必要があるかを知ることができます。ところで、 'GetPoint'はあなたの* screen *座標を取得します。これはレンダリングされたページの計算を基本にしたい場合には役に立ちません。あなたがむしろ使用するのは、 'Range.Information'オブジェクトであり、そのオブジェクトをクエリします。 'wdVerticalPositionRelativeToTextBoundary'の' wdHorizontalPositionRelativeToPage'に対してです。 –