@@ -4,54 +4,140 @@ namespace Insert_hyperlink_during_mailmerge
44{
55 class Program
66 {
7+ static Dictionary < WParagraph , List < int > > paraToInsertHyperlink = new Dictionary < WParagraph , List < int > > ( ) ;
78 public static void Main ( string [ ] args )
89 {
910 // Open the template Word document
10- WordDocument document = new WordDocument ( Path . GetFullPath ( @"Data/Template.docx" ) ) ;
11- // Attach the event handler that runs when a merge field is processed
11+ WordDocument document = new WordDocument ( Path . GetFullPath ( @"Data/EmployeesTemplate.docx" ) ) ;
12+ // Gets the employee details as IEnumerable collection.
13+ List < Employee > employeeList = GetEmployees ( ) ;
14+ // Creates an instance of MailMergeDataTable by specifying MailMerge group name and IEnumerable collection.
15+ MailMergeDataTable dataSource = new MailMergeDataTable ( "Employees" , employeeList ) ;
16+ // Uses the mail merge events handler for image fields.
17+ document . MailMerge . MergeImageField += new MergeImageFieldEventHandler ( MergeField_EmployeeImage ) ;
18+ // Uses the mail merge event handler for merge fields.
1219 document . MailMerge . MergeField += MailMerge_MergeField ;
13- // Define the merge field names present in the template document
14- string [ ] fieldNames = new string [ ] { "EmployeeId" , "Name" , "Phone" , "City" , "Contact" } ;
15- // Define the values that will replace the merge fields during mail merge
16- string [ ] fieldValues = new string [ ] { "1001" , "Peter" , "+122-2222222" , "London" , "peter@xyz.com" } ;
17- //Execute Mail merge
18- document . MailMerge . Execute ( fieldNames , fieldValues ) ;
20+ // Performs Mail merge.
21+ document . MailMerge . ExecuteGroup ( dataSource ) ;
22+ // Insert Hyperlink to the merge field text.
23+ InsertHyperlink ( document ) ;
1924 // Save the result document
2025 document . Save ( Path . GetFullPath ( @"../../../Output/output.docx" ) ) ;
2126 // Close the Word document
2227 document . Close ( ) ;
2328 }
2429 /// <summary>
25- /// Event handler that customizes how merge fields are processed.
30+ /// Event handler that customizes how merge fields are processed during mail merge .
2631 /// </summary>
2732 /// <param name="sender">The source object raising the event (MailMerge engine).</param>
2833 /// <param name="args">Provides details about the current merge field being processed</param>
2934 private static void MailMerge_MergeField ( object sender , MergeFieldEventArgs args )
3035 {
3136
32- // Check if the current merge field is "Contact", If Yes this field will be replaced with a hyperlink
37+ // Check if the current merge field is "Contact"
3338 if ( args . FieldName == "Contact" )
3439 {
35- // Create a new paragraph and append hyperlink,
36- WParagraph paragraph = new WParagraph ( args . Document ) ;
37- WField hyperlink = paragraph . AppendHyperlink ( args . FieldValue . ToString ( ) , "Click ME" , HyperlinkType . WebLink ) as WField ;
38- // Get the current merge field object being processed
39- WField mergeField = args . CurrentMergeField as WField ;
40- // Ensure the merge field exists before replacing it
41- if ( mergeField != null )
40+ // Get the mergefield's Owner paragraph
41+ WParagraph mergeFieldOwnerParagraph = args . CurrentMergeField . OwnerParagraph ;
42+ // Check if this paragraph already has an entry in the dictionary.
43+ // If not, create a new list to store field index.
44+ if ( ! paraToInsertHyperlink . TryGetValue ( mergeFieldOwnerParagraph , out var fields ) )
4245 {
43- // Get the paragraph that contains the merge field
44- WParagraph ownerParagraph = mergeField . OwnerParagraph ;
45- // Insert the child entity (e.g., hyperlink) from the new paragraph into the original paragraph
46- for ( int i = 0 ; i < paragraph . ChildEntities . Count ; i ++ )
46+ fields = new List < int > ( ) ;
47+ paraToInsertHyperlink [ mergeFieldOwnerParagraph ] = fields ;
48+ }
49+ // Add the current merge field's index
50+ fields . Add ( mergeFieldOwnerParagraph . ChildEntities . IndexOf ( args . CurrentMergeField ) ) ;
51+ }
52+ }
53+ /// <summary>
54+ /// Inserts hyperlinks into the Word document at the positions of merge fields
55+ /// </summary>
56+ /// <param name="document">The WordDocument object being processed.</param>
57+ private static void InsertHyperlink ( WordDocument document )
58+ {
59+ foreach ( KeyValuePair < WParagraph , List < int > > dictionaryItems in paraToInsertHyperlink )
60+ {
61+ // Get the paragraph where Hyperlink needs to be inserted.
62+ WParagraph paragraph = dictionaryItems . Key ;
63+ // Get the list of index for the merge fields.
64+ List < int > values = dictionaryItems . Value ;
65+ // Iterate through the list in reverse order
66+ for ( int i = values . Count - 1 ; i >= 0 ; i -- )
67+ {
68+ // Get the index of the merge field within the paragraph.
69+ int index = values [ i ] ;
70+ // Get the merge field content to insert as Hyperlink.
71+ WTextRange mergeFieldText = paragraph . ChildEntities [ index ] as WTextRange ;
72+ if ( mergeFieldText != null )
4773 {
48- int fieldIndex = ownerParagraph . ChildEntities . IndexOf ( mergeField ) ;
49- ownerParagraph . ChildEntities . Insert ( fieldIndex , paragraph . ChildEntities [ i ] . Clone ( ) ) ;
74+ WParagraph hyperlinkParagraph = new WParagraph ( document ) ;
75+ WField hyperlink = hyperlinkParagraph . AppendHyperlink ( mergeFieldText . Text . ToString ( ) , "Click ME" , HyperlinkType . WebLink ) as WField ;
76+ // Insert the child entity (e.g., hyperlink) from the new paragraph into the original paragraph
77+ for ( int j = hyperlinkParagraph . ChildEntities . Count - 1 ; j >= 0 ; j -- )
78+ {
79+ paragraph . ChildEntities . Insert ( index , hyperlinkParagraph . ChildEntities [ j ] . Clone ( ) ) ;
80+ }
81+ // Remove the original merge field text from the paragraph
82+ paragraph . ChildEntities . Remove ( mergeFieldText ) ;
5083 }
51- // Remove the original merge field from the paragraph
52- ownerParagraph . ChildEntities . Remove ( mergeField ) ;
5384 }
5485 }
86+ paraToInsertHyperlink . Clear ( ) ;
87+ }
88+ /// <summary>
89+ /// Represents the method that handles MergeImageField event.
90+ /// </summary>
91+ private static void MergeField_EmployeeImage ( object sender , MergeImageFieldEventArgs args )
92+ {
93+ //Binds image from file system during mail merge.
94+ if ( args . FieldName == "Photo" )
95+ {
96+ string photoFileName = args . FieldValue . ToString ( ) ;
97+ //Gets the image from file system.
98+ FileStream imageStream = new FileStream ( Path . GetFullPath ( @"Data/" + photoFileName ) , FileMode . Open , FileAccess . Read ) ;
99+ args . ImageStream = imageStream ;
100+ }
101+ }
102+ /// <summary>
103+ /// Gets the employee details to perform mail merge.
104+ /// </summary>
105+ public static List < Employee > GetEmployees ( )
106+ {
107+ List < Employee > employees = new List < Employee > ( ) ;
108+ employees . Add ( new Employee ( "Nancy" , "Smith" , "Sales Representative" , "505 - 20th Ave. E. Apt. 2A," , "Seattle" , "WA" , "USA" , "nancy.smith@xyz.com" , "Nancy.png" ) ) ;
109+ employees . Add ( new Employee ( "Andrew" , "Fuller" , "Vice President, Sales" , "908 W. Capital Way" , "Tacoma" , "WA" , "USA" , "andrew.fuller@xyz.com" , "Andrew.png" ) ) ;
110+ employees . Add ( new Employee ( "Roland" , "Mendel" , "Sales Representative" , "722 Moss Bay Blvd." , "Kirkland" , "WA" , "USA" , "roland.mendel@xyz.com" , "Janet.png" ) ) ;
111+ employees . Add ( new Employee ( "Margaret" , "Peacock" , "Sales Representative" , "4110 Old Redmond Rd." , "Redmond" , "WA" , "USA" , "margaret.peacock@xyz.com" , "Margaret.png" ) ) ;
112+ employees . Add ( new Employee ( "Steven" , "Buchanan" , "Sales Manager" , "14 Garrett Hill" , "London" , string . Empty , "UK" , "steven.buchanan@xyz.com" , "Steven.png" ) ) ;
113+ return employees ;
114+ }
115+ /// <summary>
116+ /// Represents a class to maintain employee details.
117+ /// </summary>
118+ public class Employee
119+ {
120+ public string FirstName { get ; set ; }
121+ public string LastName { get ; set ; }
122+ public string Address { get ; set ; }
123+ public string City { get ; set ; }
124+ public string Region { get ; set ; }
125+ public string Country { get ; set ; }
126+ public string Title { get ; set ; }
127+ public string Contact { get ; set ; }
128+ public string Photo { get ; set ; }
129+ public Employee ( string firstName , string lastName , string title , string address , string city , string region , string country , string contact , string photoFilePath )
130+ {
131+ FirstName = firstName ;
132+ LastName = lastName ;
133+ Title = title ;
134+ Address = address ;
135+ City = city ;
136+ Region = region ;
137+ Country = country ;
138+ Contact = contact ;
139+ Photo = photoFilePath ;
140+ }
55141 }
56142 }
57143}
0 commit comments