InfoPath: Copying File Attachments from one section to another

If you have worked with InfoPath, you'll agree one has to come up with different techniques and tricks to implement solutions that are not available out-of-the-box.

In this article, I present a technique using which you can copy file attachments from one section to another. There are different scenarios in which you may want to do this. For example, consider a situation where you want to restrict users from deleting attachments once uploaded. Properties of file attachment control can only be set at design time and these properties once set cannot be changed dynamically. You can either allow users to insert/delete files or disallow them inserting or deleting files. Solution is to use two attachment controls and copy the content of one control to the other when user saves the form. One control will allow inserting/deleting files. The control will not allow inserting or deleting files and if you want to upload multiple files, then put the file attachment control in a repeating section. In this case, the read-only file attachment control should also be put in a repeating section. The source and destination data nodes hierarchy should be same otherwise copying of content will not work.

1. Start InfoPath 2007. Click "Data Source" in "Design Tasks".

Design Tasks

Fig 1: Data Source (Design Tasks)

2.  Right-click "myFields" and select "Add..." from the menu.

Add

Fig 2: Add node

3. Add name "group1" and from "Type" select "Group". Click OK.



Fig 3: Add group

4. Right-click newly added group "group1" and select "Add..." from the menu.  Enter "repGroup1" in the "Name" field and select "Group" from the "Type" field. Check "Repeating" checkbox at the bottom. This is important because this will be a repeating group. This repeating group will hold multiple file attachment controls.



Fig 4: Add repeating group

5. Drag repeating group "repGroup1" and drop it on the form. This will insert a repeating section in the form.

6. Click "Design Tasks" and then click "Controls". From the controls panel, select "File Attachment" control and add it to the repeating section. Make sure the cursor is inside the repeating section and then double-click "File Attachment" control. This will insert the control in the repeating section.

7. Click "Design Tasks" again and select "Data Source". Right-click "myFields" and select "Add...". Enter "group2" in the "Name" field and select "Group" in the "Type" field. Click Ok. This will create a new non-repeating group. Our goal is to create a new section with file attachment control but in this case, we will now allow inserting or deleting files. In other words, it will be a read-only section with read-only file attachment control.



Fig 5: Add destination group

8. Right-click "repGroup1" and select "Reference..." from the menu. Select "group2" from the list and click "OK". This will add a repeating group and a data node in the "group2" node.

9. Drag "repGroup1" from "group2" and drop it on the form. Select repeating section from the menu that opens. This will add an empty repeating section on the form. Drag "field1" from "group2" and drop it inside the newly added repeating section. Now  you have two identical repeating sections in the form. Advantage of using repeating section is, user can add as many file attachments as he or she likes.

10. Right-click second repeating section and select "Repeating Section Properties..." from the options menu. Uncheck "Allow users to insert and delete the sections". Click "OK".

11. Right-click second file attachment control and select "File Attachment Properties..." from the menu. Uncheck "Allow the user to browse, delete, and replace files" and click "OK".



Fig 6: Make file attachment read-only

12. Add a button to the form (Design Tasks > Controls).

13. Select "Form Options" from the "Tools" menu.



Fig 7: Form Options

14. Select "Programming" category. Select "C#" in the "Form template code language". Click "OK".



Fig 8: Select programming language

15. Double-click button and select "Edit Form Code". You will be prompted to save the form if you had not saved it already. Click "Ok". Give an appropriate name to your form. I kept the default name "Template1.xsn". This will create a new C# project for you. The location of the project, by default, will be as follows:

C:\Documents and Settings\Administrator\My Documents\InfoPath Projects\Template11\Template1.csproj

Note, you can change this location by going to Tools > Form Options and then by selecting "Programming" from the categories. Change the location in the field called "Project location for VB and C# code". This field is located at the bottom.

16. Copy following code to the project:

private void CopyAttachments()

{

string srcXPath = "/my:myFields/my:group1";

string destXPath = "/my:myFields/my:group2";

string srcNodeXPath = "/my:myFields/my:group1/repGroup1";

XPathNavigator source = this.CreateNavigator().SelectSingleNode(srcXPath, this.NamespaceManager);

XPathNavigator dest = this.CreateNavigator().SelectSingleNode(destXPath, this.NamespaceManager);

if (dest.MoveToAttribute("nil", "http://www.w3.org/2001/XMLSchema-instance"))

dest.DeleteSelf();

if (source.InnerXml.Contains("xsi:nil="))

{

//Do nothing

}

else

{

if (dest.InnerXml.Contains("xsi:nil="))

{

dest.InnerXml = source.InnerXml;

}

else

{

dest.InnerXml += source.InnerXml;

}

//clear source files

XPathNavigator srcFiles = this.CreateNavigator().SelectSingleNode(srcNodeXPath, this.NamespaceManager);

if (IsGridDirty(srcNodeXPath))

{

XPathNodeIterator Node_To_Be_Deleted = this.CreateNavigator().Select(srcNodeXPath, NamespaceManager);

string groupResults = srcNodeXPath;

XPathNavigator firstItem;

XPathNavigator lastItem;

if (Node_To_Be_Deleted.Count > 1)

{

firstItem = srcFiles.SelectSingleNode(groupResults + "[1]", NamespaceManager);

lastItem = srcFiles.SelectSingleNode(groupResults + "[position()=last()]", NamespaceManager);

firstItem.DeleteRange(lastItem);

//clean up local variables

lastItem = null;

firstItem = null;

}

else if (Node_To_Be_Deleted.Count == 1)

{

firstItem = srcFiles.SelectSingleNode(groupResults + "[1]", NamespaceManager);

firstItem.DeleteSelf();

}

//clean up

Node_To_Be_Deleted = null;

}

//clean up

srcFiles = null;

}

}

private bool IsGridDirty(string ControlName)

{

try

{

//This function checks whether the Results node has any items or not, returns true if the number of items is greater than 0.

XPathNavigator _DOM = this.MainDataSource.CreateNavigator();

XPathNodeIterator nodes = _DOM.Select(ControlName, this.NamespaceManager);

XPathNavigator nodesNavigator = nodes.Current;

XPathNodeIterator nodesText = nodesNavigator.SelectDescendants(XPathNodeType.Text, false);

int counter = 0;

while (nodesText.MoveNext())

{

if (nodesText.Current.NodeType == XPathNodeType.Text)

{

//if (nodesText.Current.Name == "Section5_Selected" && (nodesText.Current.Value == "true" || nodesText.Current.Value == "false" || nodesText.Current.Value == "" || nodesText.Current.Value == "blank"))

//{

counter += 1;

//}

}

}

//clean up

nodesText = null;

nodesNavigator = null;

nodes = null;

_DOM = null;

//return count

if (counter > 0)

{

return true;

}

else

{

return false;

}

}

catch (Exception ex)

{

return false;

}

}



Check these lines:

string srcXPath = "/my:myFields/my:group1";

string destXPath = "/my:myFields/my:group2";

string srcNodeXPath = "/my:myFields/my:group1/repGroup1";

Paths should be correct. srcXPath contains the xPath of the source group, that is, group1. destXPath contains the xPath for the destination group, that is, group2. srcNodeXPath contains the xPath of first repeating group.


16. Call "CopyAttachments()" in the button's click:

public void CTRL5_5_Clicked(object sender, ClickedEventArgs e)

{

CopyAttachments();

}

 

17. Save the project, compile it and publish the form. Add attachments to the first repeating section and click the button. The files will be copied to the second repeating section and cleared from the first repeating section. Now users cannot delete files from the second repeating section. Usually this function is called when the form is submitted because before the form is saved or submitted, user can change the files.