Reply
 
Thread Tools Display Modes
  #1   Report Post  
Posted to microsoft.public.word.mailmerge.fields
eJimmi eJimmi is offline
external usenet poster
 
Posts: 3
Default Header / Footer mail merge issue with custom built word automation solution.

Office professional 2003
Visual studio 2005
C#
Example mail merge field from header: «Field:Name»

I have smart client that use web services to provide data for mail
merge. The templates contain Custom tokens inserted in the document as
mail merge fields eg {{Field:StudentNumber}}, {{Table:CourseUnits}}.
The client parses the tokens and populates document with the relevant
data. All works well until these fields are in the header or footer.

The main method for performing the merge loops through the supplied
data rows and calls the ProcessFields method passing in the fields
collection from the document, header and footer.


Code stub from the execute method
DataRowCollection rows = _Data.Tables[0].Rows;
for (int i=0; i rows.Count; i++)
{
Word.Document document = null;
if (_DocumentType == DocumentType.Template)
{
document = _Assistant.AddDocument(_FilePath, true);
}
else
{
document = _Assistant.OpenDocument(_FilePath, true);
}
if (_BeforeRowProcessed != null)
{
_BeforeRowProcessed(this, document, rows[i], i);
}
// document.MailMerge.Destination = _Destination;
Word.HeaderFooter header =
document.Sections[1].Headers[Word.WdHeaderFooterIndex.wdHeaderFooterPrimary];
if (header.Exists)
{
ProcessFields(header.Range.Fields, rows[i]);
}
ProcessFields(document.Fields, rows[i]);
Word.HeaderFooter footer =
document.Sections[1].Footers[Word.WdHeaderFooterIndex.wdHeaderFooterPrimary];
if (footer.Exists)
{
ProcessFields(footer.Range.Fields, rows[i]);
}
if (_AfterRowProcessed != null)
{
_AfterRowProcessed(this, document, rows[i], i);
}
}


private void ProcessFields(Word.Fields fields, DataRow row)
{
foreach (Word.Field field in fields)
{
field.Select();
Word.Range range = _Assistant.Application.Selection.Range;
if (_OnFieldSelect != null)
{
_OnFieldSelect(this, field, row);
}
ResolveToken(field, row);
}
}


The resolve ResolveToken method maps the word merge field to the
database field writing the text with:

field.Result.Text = DatabaseAssistant.SafeStringValue(row[tokenKey]);

The best I have mamanged is to have either of the header or footer edit
pane open with the resolved value however when I close the window the
merge field only is displayed - the value is gone. I cannot see the
value in the print preview either. Initially I'm only concerned with
the primary header or footer - old tackle the variations of headers /
footers at a later stage.

This is the first Word automation I've built so any pointers will be
appreciated.

JS

  #2   Report Post  
Posted to microsoft.public.word.mailmerge.fields
Cindy M -WordMVP- Cindy M  -WordMVP- is offline
external usenet poster
 
Posts: 370
Default Header / Footer mail merge issue with custom built word automation solution.

Hi Jimmi,

Hmmm. "Mail merge" is a very specific thing in Word terminology. Given that
you're working with a web service, you can't be doing a true mail merge, so you
shouldn't use that term when discussing your project - it confuses people like
us :-)

OK, so you're passing data into "targets" in a Word document, and you've chosen
to use Mergefields (I guess, it's hard to be sure if that's what you really
have) as the targets. This works in the body of the document, but not in the
header/footer.

The reason is fairly clear: you're trying to use the Selection object. Fact is,
physically selecting a header/footer via automation in a Word document just
doesn't work very well. Actually, you should avoid *selecting* anything when
automating Word, unless there's no other way to accomplish the task.

It's much better to work exclusively (if possible) with the RANGE object. You
do this up the point of passing control to the ProcessFields method. A field
obejct doesn't have a Range property, but it does have a Result property which
returns a Range. You do not have to select the field in order to access the
Result property.

Next problem: Word fields are actually dynamic entities - they aren't meant to
serve as "data targets". With one single exception (form fields), if you assign
something to Field.Result.Text that information will be lost as soon as the
field receives a command to update (such as pressing F9 when the field is
selected). This is how Word is designed to work.

If the data you're passing in should be permanent, then you should work more
like this:
Word.Field fld = footer.Fields[i];
Word.Range rng = fld.Result;
fld.Delete;
rng.Text = "my data";
[i]
Office professional 2003
Visual studio 2005
C#
Example mail merge field from header: «Field:Name»

I have smart client that use web services to provide data for mail
merge. The templates contain Custom tokens inserted in the document as
mail merge fields eg {{Field:StudentNumber}}, {{Table:CourseUnits}}.
The client parses the tokens and populates document with the relevant
data. All works well until these fields are in the header or footer.

The main method for performing the merge loops through the supplied
data rows and calls the ProcessFields method passing in the fields
collection from the document, header and footer.


Code stub from the execute method
DataRowCollection rows = Data.Tables[0].Rows;
for (int i=0; i rows.Count; i++)
{
Word.Document document = null;
if ( DocumentType == DocumentType.Template)
{
document = Assistant.AddDocument( FilePath, true);
}
else
{
document = Assistant.OpenDocument( FilePath, true);
}
if ( BeforeRowProcessed != null)
{
BeforeRowProcessed(this, document, rows[i], i);
}
// document.MailMerge.Destination = Destination;
Word.HeaderFooter header =
document.Sections[1].Headers[Word.WdHeaderFooterIndex.wdHeaderFooterPrimary];
if (header.Exists)
{
ProcessFields(header.Range.Fields, rows[i]);
}
ProcessFields(document.Fields, rows[i]);
Word.HeaderFooter footer =
document.Sections[1].Footers[Word.WdHeaderFooterIndex.wdHeaderFooterPrimary];
if (footer.Exists)
{
ProcessFields(footer.Range.Fields, rows[i]);
}
if ( AfterRowProcessed != null)
{
AfterRowProcessed(this, document, rows, i);
}
}


private void ProcessFields(Word.Fields fields, DataRow row)
{
foreach (Word.Field field in fields)
{
field.Select();
Word.Range range = Assistant.Application.Selection.Range;
if ( OnFieldSelect != null)
{
OnFieldSelect(this, field, row);
}
ResolveToken(field, row);
}
}


The resolve ResolveToken method maps the word merge field to the
database field writing the text with:

field.Result.Text = DatabaseAssistant.SafeStringValue(row[tokenKey]);

The best I have mamanged is to have either of the header or footer edit
pane open with the resolved value however when I close the window the
merge field only is displayed - the value is gone. I cannot see the
value in the print preview either. Initially I'm only concerned with
the primary header or footer - old tackle the variations of headers /
footers at a later stage.

This is the first Word automation I've built so any pointers will be
appreciated.


Cindy Meister
INTER-Solutions, Switzerland
http://homepage.swissonline.ch/cindymeister (last update Jun 17 2005)
http://www.word.mvps.org

This reply is posted in the Newsgroup; please post any follow question or reply
in the newsgroup and not by e-mail :-)

  #3   Report Post  
Posted to microsoft.public.word.mailmerge.fields
eJimmi eJimmi is offline
external usenet poster
 
Posts: 3
Default Header / Footer mail merge issue with custom built word automation solution.

Hi Cindy

Thank you so much for your advice. I could not have built a solution
without your website and contributions to the newsgroups from yourself
and the other contributing MVP's.

Re "word terminology" and "Mail Merge" - I agree, and have
adopted the "targets" term in my documentation. You are correct in
your deductions - and I am using the fields as data targets and the
data I'm passing in is to be permanent. I have implemented your
suggested code block and it works beautifully.

As I'm not performing a mail merge (there is no
document.MailMerge.DataSource) I'm assuming I will need to implement my
own custom code to emulate the
WdMailMergeDestination.wdSendToNewDocument..wdSend ToPrinter
functionality? I'm pretty sure I already know the answer.

Many thanks again

Jaimie Sims (e-Jimmi).

  #4   Report Post  
Posted to microsoft.public.word.mailmerge.fields
Cindy M -WordMVP- Cindy M  -WordMVP- is offline
external usenet poster
 
Posts: 370
Default Header / Footer mail merge issue with custom built word automation solution.

Hi Jaimie,

As I'm not performing a mail merge (there is no
document.MailMerge.DataSource) I'm assuming I will need to implement my
own custom code to emulate the
WdMailMergeDestination.wdSendToNewDocument..wdSend ToPrinter
functionality? I'm pretty sure I already know the answer.

LOLYes, in that case you do have to code it all. Question then becomes,
of course, what's the most efficient approach.

One possibility would be to close the document and start over again with
a new copy. But that would be comparatively slow.

I might be more inclined to begin by setting a BOOKMARK around each
mergefield target (do that in your loop, rather than writing in the
text).

Then loop. In the loop, write the text to Bookmark.Range.Text (which
should remove the mergefield on the first pass), and then recreate the
bookmark so that it will always be there. Very roughly, in VBA-speak:
Dim rng as Word.Range
Dim bkmName as String

Set rng = document.Bookmarks(bkmName).Range
rng.Text = "the data"
document.Bookmarks.Add Name:=bkmName, Range:=rng

Cindy Meister
INTER-Solutions, Switzerland
http://homepage.swissonline.ch/cindymeister (last update Jun 17 2005)
http://www.word.mvps.org

This reply is posted in the Newsgroup; please post any follow question or
reply in the newsgroup and not by e-mail :-)

  #5   Report Post  
Posted to microsoft.public.word.mailmerge.fields
eJimmi eJimmi is offline
external usenet poster
 
Posts: 3
Default Header / Footer mail merge issue with custom built word automation solution.

Hi Cindy

Thanks again for going the extra yards. I'll look at implmenting this
in the coming weeks (other bigger fires to deal with now).

take care
JS

Then loop. In the loop, write the text to Bookmark.Range.Text (which
should remove the mergefield on the first pass), and then recreate the
bookmark so that it will always be there. Very roughly, in VBA-speak:
Dim rng as Word.Range
Dim bkmName as String

Set rng = document.Bookmarks(bkmName).Range
rng.Text = "the data"
document.Bookmarks.Add Name:=bkmName, Range:=rng


Reply
Thread Tools
Display Modes

Posting Rules

Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Header and Footer MoPete99 Microsoft Word Help 20 July 25th 06 11:07 AM
Word & WordPerfect MrsMac Microsoft Word Help 5 June 10th 06 03:14 AM
Pre-set Query Conditions that cannot be changed Charity Event Secretary Mailmerge 4 April 17th 06 05:56 PM
Using Word Mail Merge feature for custom templates S.Sanghani Mailmerge 3 January 11th 06 11:22 AM
Specific Email Merge w/ Specific Attachements Mark B Mailmerge 9 February 21st 05 06:10 AM


All times are GMT +1. The time now is 02:45 PM.

Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Copyright ©2004-2024 Microsoft Office Word Forum - WordBanter.
The comments are property of their posters.
 

About Us

"It's about Microsoft Word"