Welcome to MSDN Blogs Sign in | Join | Help

InfoPath Team Blog

Tips and tricks to get the most out of Microsoft InfoPath

News

  • For questions, comments, and feedback please use the public newsgroup: microsoft.public.infopath
    This is provided "AS IS" with no warranties, and confers no rights. Use of included script samples and forms are subject to the terms specified in the Terms of Use.
Another Way of Sorting Repeating Data

If you have ever attempted to sort repeating node data (i.e. a Repeating Table or Repeating Section) on an InfoPath form, you will find this functionality is not available through the UI. However, using .NET classes you can easily implement a sorting routine that will work in both client and browser scenarios. We discussed one way to make this happen through custom code in a recent article; this post will show a different way to make it happen. We will take a look at how to implement this functionality along with taking advantage of some new features in InfoPath 2007:

  • Dynamic button labels
  • Complex default value on the Button label to change the caption based on the sort order of the selected field (discussed in this article)

In this sample scenario, let’s assume you are capturing the following data in a Repeating Table:

  • Last Name (name: LastName)
  • First Name (name: FirstName)
  • Age (name: Age)

In addition, you want to allow your users to select the field they want to sort on (using a button in the column header) and clicking the button will toggle the sort between Ascending and Descending. Here is a sample form showing those options:

** NOTE: Notice the “(Asc)” in the Last Name button label? We’ll show you how to do that at the end of this post!

The data structure for the above sample is as follows:

So in this scenario, the user would simply click the button above the field they want to use to sort the data and by default, the first click would sort the data in Ascending order and clicking it again would sort the data in Descending order. Let’s now go ahead and take a look at the code on the click event of the buttons that implements this functionality.

When each button is clicked, the first thing we do is set the value of the SortOrder and SortField nodes. For ease of implementation, we created a “SpecifySortOptions” procedure that is called from the click event of each button:

SpecifySortOptions("LastName",XmlDataType.Text,e.ControlId);

When each button is clicked we call this procedure passing it the field we want to use for sorting (in this case, LastName), the data type of this field (XmlDataType.Text) and the ControlID of the button that was clicked. (The ControlID is used in the Expression for the Default Value property of each button to determine how to change the label.)

Here is the SpecifySortOptions procedure:

public void SpecifySortOptions(string SortField, XmlDataType dataType, string ControlID)

{

//Create Navigator objects for the main DOM and

//for the SortOrder and SortField fields

XPathNavigator xn = this.MainDataSource.CreateNavigator();

XPathNavigator xnSortOrder = xn.SelectSingleNode("/my:myFields/my:SortOrder", this.NamespaceManager);

XPathNavigator xnSortField = xn.SelectSingleNode("/my:myFields/my:SortField", this.NamespaceManager);

 

//Check to see if the value of the SortField is equal

//to the ControlID that we passed to this procedure. If

//it is the same and the SortOrder field is an SortOrder

//emptry string or is set to "Desc" then set the field to

//"Asc". If the SortField value does not equal the

//ControlID that we passed to this procedure, then that

//would mean either the SortField is an empty string or

//it was set to another field - either way, we will

//then want the SortOrder value to be "Asc"

if (xnSortField.Value == ControlID)

{

   if (xnSortOrder.Value == "" || xnSortOrder.Value == "Desc")

      xnSortOrder.SetValue("Asc");

   else

      xnSortOrder.SetValue("Desc");

}

else

   xnSortOrder.SetValue("Asc");

 

//Call the SortTheData() procedure passing in the values

//specified above

SortTheData(SortField, xnSortOrder.Value, dataType);

 

//Set the SortField value to the current ControlID

xnSortField.SetValue(ControlID);

}

After calling the SpecifySortOptions procedure from the click event of each button, this procedure calls the SortTheData procedure, which accepts a string value for the sort field (strSortField), a string value for the sort order (strSortOrder) and an XmlDataType value (dataType) for the type of data being sorted. This is the code that will actually perform the sorting.

The first thing we need to do is this procedure is create “XPathNavigator” objects for the main DOM:

//Create a Navigator object for the main DOM

XPathNavigator xn = this.MainDataSource.CreateNavigator();

We then will create an XmlSortOrder object so we can specify either an Ascending or Descending sort. In this sample, we will specify an Ascending sort as the default; however, we will check the value of strSortOrder and if this is set to “Desc”, change the XmlSortOrder object accordingly:

XmlSortOrder sortOrder = XmlSortOrder.Ascending;

if (strSortOrder == "Desc")

sortOrder = XmlSortOrder.Descending;

To actually perform the sort, we will be using the “AddSort” method of an XPathExpression object – as such, we need to create an XPathExpression object for the repeating (group) node that we are going sort:

XPathExpression xe = xn.Compile("/my:myFields/my:group1/my:group2");

Now we can use the AddSort method on the Expression object using the field name (strSortField) that we passed into this procedure, the sort order using the sort order object (sortOrder) we created above and the data type using the data type object (dataType) we passed into this procedure:

xe.AddSort("*[local-name()='" + strSortField + "']", sortOrder, XmlCaseOrder.None, "", dataType);

We need to specify a NamespaceManager for the Expression object and for this we will use the SetContext method:

xe.SetContext(this.NamespaceManager);

The next step is to create an XPathNodeIterator object, passing it our XPathExpression object, so we can iterate all the nodes now that they are sorted - in addition, we will use this object (in the lastNode expression below) to get a count of the total nodes in this repeating group:

XPathNodeIterator xi = xn.Select(xe);

In the end, the way this procedure works is to delete the existing “un-sorted” nodes and add back the “sorted” nodes via the XPathNodeIterator object. So the next step is to now delete the existing “un-sorted” data. To do this, we will create XPathNavigator objects to reference the first and last nodes in this repeating group and then use the DeleteRange method to delete those nodes:

XPathNavigator firstNode = xn.SelectSingleNode("/my:myFields/my:group1/my:group2[1]", this.NamespaceManager);

XPathNavigator lastNode = xn.SelectSingleNode("/my:myFields/my:group1/my:group2[" + xi.Count + "]", this.NamespaceManager);

firstNode.DeleteRange(lastNode);

At this point, we have the sorted data in memory and the un-sorted data has been removed so we are ready to add that sorted data back to the form. For this process, we will use the XPathNodeIterator object we created earlier to iterate over the nodes.

while (xi.MoveNext())

{

//Create string variables to hold the values of each field

//as we iterate the nodes

string strLastName = xi.Current.SelectSingleNode("my:LastName", this.NamespaceManager).Value;

string strFirstName = xi.Current.SelectSingleNode("my:FirstName", this.NamespaceManager).Value;

string strAge = xi.Current.SelectSingleNode("my:Age", this.NamespaceManager).Value;

 

//Call the AddNewRow method to append a new row

// to the repeating group

AddNewRow(xn.SelectSingleNode("/my:myFields/my:group1", this.NamespaceManager));

 

//Since we are continually appending new rows, the 

//"last" row will always be the one where we need

//to set the values - so here we will create a

//Navigator object for this newly added row - we

//will use this for setting the field values below

XPathNavigator xnNewRow = xn.SelectSingleNode("/my:myFields/my:group1/my:group2[last()]", this.NamespaceManager);

 

xnNewRow.SelectSingleNode("my:LastName", this.NamespaceManager).SetValue(strLastName);

xnNewRow.SelectSingleNode("my:FirstName", this.NamespaceManager).SetValue(strFirstName);

 

//Since the Age field is numeric, it will contain

//the "nil" attribute. We need to remove this

//arrtibute prior to programmatically setting the

//value. To do this, we'll call the DeleteNil

//procedure passing it the node that contains

//(or may contain) the nil attribute

DeleteNil(xnNewRow.SelectSingleNode("my:Age", this.NamespaceManager));

 

//Now we can set the value of the Age field

xnNewRow.SelectSingleNode("my:Age", this.NamespaceManager).SetValue(strAge);

}

In the while loop above, we used the “AddNewRow” and “DeleteNil” procedures – these are documented below:

public void AddNewRow(XPathNavigator docXN)

{

//Create a Navigator object to reference the node

//we will be adding. To do this, we can use the

//templates' "Manifest.xsf" file to get the

//appropriate node to add. As you can see, this is

//specific to the control's "name", which you can

//get from the Advanced tab on the Properties window

//for the repeating control. Once you have this,

//use the "Save As Source Files" command from the 

//File menu in InfoPath and locate the appropriate

//expression in your Manifest.xsf file

XPathNavigator xnNode = this.Template.Manifest.SelectSingleNode("//xsf:xDocumentClass/xsf:views/xsf:view/xsf:editing/xsf:xmlToEdit[@name='group2_1']/xsf:editWith/xsf:fragmentToInsert/xsf:chooseFragment/my:group1", this.NamespaceManager);     

 

//Append the node from the Manifest file to the main DOM

docXN.SelectSingleNode("/my:myFields/my:group1", this.NamespaceManager).AppendChild(xnNode.InnerXml);

}

 

public void DeleteNil(XPathNavigator node)

{

//Check to see if the nil attribute exists

//and if so, delete it

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

    node.DeleteSelf();

}

And that’s it! You now have the functionality of sorting data in a repeating node. For reference, the complete code for this sample is attached.

Now – about that button label…how did we do that??!

With InfoPath 2007, we have a new feature that allows you to specify a dynamic value for the button label. To do this, simply click the “fx” button next to the label property and you can choose to use an expression of a field/group from your form:

However, for this sample the conditional logic for the button label is quite complex: we need to determine which button was clicked and whether we should show “(Asc)” or “(Desc)” next to the correct label. For this, we used the process demonstrated in this blog post: Conditional Default Values.
So here is the logic that needed to be implemented when each button is clicked; for example, for the Last Name button:

  • See if the SortField value (which is set to a button’s ControlID in the SpecifySortOptions procedure) is equal to the clicked button’s ControlID and if the SortOrder value is either an empty string or equal to “Asc”
    • If it is, then set the label to: Last Name (Asc)
  • See if the SortField value is equal to the clicked button’s ControlID and the SortOrder value is “Desc”
    • If it is, then set the lable to: Last Name (Desc)
  • If neither of the above are true, then a different button must have been clicked so set the label to: Last Name

This is the logic that needs to be implemented for each button. Here is a sample expression for the LastName field:

concat(substring("Last Name (Asc)", 1, ((my:SortOrder = "" or my:SortOrder = "Asc") and my:SortField = "btnLastName") * string-length("Last Name (Asc)")), substring("Last Name (Desc)", 1, (my:SortOrder = "Desc" and my:SortField = "btnLastName") * string-length("Last Name (Desc)")), substring("Last Name", 1, not(my:SortField = "btnLastName") * string-length("Last Name")))

Each of the above “substring” expressions are tested in order – so if the SortOrder field does not equal an empty string or does not equal “Asc” and the SortField value does not equal “btnLastName” then we test the next condition. If the SortOrder value does not equal “Desc” and the SortField value does not equal “btnLastName” then we test the last condition. And here we only need to check the value of my:SortField – if this does not equal “btnLastName” then we know a different button was clicked and we only want the label to display “Last Name”.

So there you have it! A way to sort data in your repeating table and a really cool way to let the user know which field they clicked for sorting and in which order the data has been sorted!

** NOTE: It seems we may have a bug with our expression box in that it will accept the entire conditional statement noted above but once you close and re-open the box, the string gets truncated. Once you have this working, you may want to keep that expression saved in a text file.

Scott Heim
Support Engineer

Posted: Friday, December 15, 2006 8:57 AM by infopath
Filed under:

Attachment(s): sortingData_sample_cs.txt

Comments

BobC said:

Why would the AppendRow fail "with a non data-type error"?

# March 4, 2008 11:35 AM

BobC said:

Found that if the schema was a single level, ie:

my:myFields/my:group1

and you are trying to add the repeating group called Activity, it won't work.  You need to have a schema with an intermediate group, followed by the repeating group, like this:

my:myFields/my:group1/my:group2

Then the AppendChild will work.

# March 4, 2008 2:46 PM

infopath said:

Hi BobC,

Glad you were able to get it to work.

Scott

# March 4, 2008 5:11 PM

All About SharePoint - S.S. Ahmed - MVP Microsoft SharePoint said:

I have already given a programmatic solution of sorting a repeating table in InfoPath but here is another

# February 3, 2009 8:04 PM

spawforths said:

I have not been able to get this to work with Infopath 2007 it just comes back and says that the form cannot be opened.

Is there downloadable example of the form?

# February 25, 2009 6:05 AM

infopath said:

Hi spawforths,

I apologize as I am not sure what happened to the attachment with the completed code; however, here are all the procedures as I documented them in this post. If you followed the naming conventions in this sample you should be able to copy and paste the code in each procedure. NOTE: For ease, I named by buttons as follows:

btnLastName

btnFirstName

btnAge

public void btnLastName_Clicked(object sender, ClickedEventArgs e)

       {

           SpecifySortOptions("LastName", XmlDataType.Text, e.ControlId);

       }

       public void btnFirstName_Clicked(object sender, ClickedEventArgs e)

       {

           SpecifySortOptions("FirstName", XmlDataType.Text, e.ControlId);

       }

       public void btnAge_Clicked(object sender, ClickedEventArgs e)

       {

           SpecifySortOptions("Age", XmlDataType.Text, e.ControlId);

       }

       public void SpecifySortOptions(string SortField, XmlDataType dataType, string ControlID)

       {

           //Create Navigator objects for the main DOM and

           //for the SortOrder and SortField fields

           XPathNavigator xn = this.MainDataSource.CreateNavigator();

           XPathNavigator xnSortOrder = xn.SelectSingleNode("/my:myFields/my:SortOrder", this.NamespaceManager);

           XPathNavigator xnSortField = xn.SelectSingleNode("/my:myFields/my:SortField", this.NamespaceManager);

           //Check to see if the value of the SortField is equal

           //to the ControlID that we passed to this procedure. If

           //it is the same and the SortOrder field is an SortOrder

           //emptry string or is set to "Desc" then set the field to

           //"Asc". If the SortField value does not equal the

           //ControlID that we passed to this procedure, then that

           //would mean either the SortField is an empty string or

           //it was set to another field - either way, we will

           //then want the SortOrder value to be "Asc"

           if (xnSortField.Value == ControlID)

           {

               if (xnSortOrder.Value == "" || xnSortOrder.Value == "Desc")

                   xnSortOrder.SetValue("Asc");

               else

                   xnSortOrder.SetValue("Desc");

           }

           else

               xnSortOrder.SetValue("Asc");

           //Call the SortTheData() procedure passing in the values

           //specified above

           SortTheData(SortField, xnSortOrder.Value, dataType);

           //Set the SortField value to the current ControlID

           xnSortField.SetValue(ControlID);

       }

       public void SortTheData(string strSortField, string strSortOrder, XmlDataType dataType)

       {

           //Create a Navigator object for the main DOM

           XPathNavigator xn = this.MainDataSource.CreateNavigator();

           XmlSortOrder sortOrder = XmlSortOrder.Ascending;

           if (strSortOrder == "Desc")

               sortOrder = XmlSortOrder.Descending;

           XPathExpression xe = xn.Compile("/my:myFields/my:group1/my:group2");

           xe.AddSort("*[local-name()='" + strSortField + "']", sortOrder, XmlCaseOrder.None, "", dataType);

           xe.SetContext(this.NamespaceManager);

           XPathNodeIterator xi = xn.Select(xe);

           XPathNavigator firstNode = xn.SelectSingleNode("/my:myFields/my:group1/my:group2[1]", this.NamespaceManager);

           XPathNavigator lastNode = xn.SelectSingleNode("/my:myFields/my:group1/my:group2[" + xi.Count + "]", this.NamespaceManager);

           firstNode.DeleteRange(lastNode);

           while (xi.MoveNext())

           {

               //Create string variables to hold the values of each field

               //as we iterate the nodes

               string strLastName = xi.Current.SelectSingleNode("my:LastName", this.NamespaceManager).Value;

               string strFirstName = xi.Current.SelectSingleNode("my:FirstName", this.NamespaceManager).Value;

               string strAge = xi.Current.SelectSingleNode("my:Age", this.NamespaceManager).Value;

               //Call the AddNewRow method to append a new row

               // to the repeating group

               AddNewRow(xn.SelectSingleNode("/my:myFields/my:group1", this.NamespaceManager));

               //Since we are continually appending new rows, the  

               //"last" row will always be the one where we need

               //to set the values - so here we will create a

               //Navigator object for this newly added row - we

               //will use this for setting the field values below

               XPathNavigator xnNewRow = xn.SelectSingleNode("/my:myFields/my:group1/my:group2[last()]", this.NamespaceManager);

               xnNewRow.SelectSingleNode("my:LastName", this.NamespaceManager).SetValue(strLastName);

               xnNewRow.SelectSingleNode("my:FirstName", this.NamespaceManager).SetValue(strFirstName);

               //Since the Age field is numeric, it will contain

               //the "nil" attribute. We need to remove this

               //arrtibute prior to programmatically setting the

               //value. To do this, we'll call the DeleteNil

               //procedure passing it the node that contains

               //(or may contain) the nil attribute

               DeleteNil(xnNewRow.SelectSingleNode("my:Age", this.NamespaceManager));

               //Now we can set the value of the Age field

               xnNewRow.SelectSingleNode("my:Age", this.NamespaceManager).SetValue(strAge);

           }

       }

       public void AddNewRow(XPathNavigator docXN)

       {

           //Create a Navigator object to reference the node

           //we will be adding. To do this, we can use the

           //templates' "Manifest.xsf" file to get the

           //appropriate node to add. As you can see, this is

           //specific to the control's "name", which you can

           //get from the Advanced tab on the Properties window

           //for the repeating control. Once you have this,

           //use the "Save As Source Files" command from the  

           //File menu in InfoPath and locate the appropriate

           //expression in your Manifest.xsf file

           XPathNavigator xnNode = this.Template.Manifest.SelectSingleNode("//xsf:xDocumentClass/xsf:views/xsf:view/xsf:editing/xsf:xmlToEdit[@name='group2_1']/xsf:editWith/xsf:fragmentToInsert/xsf:chooseFragment/my:group1", this.NamespaceManager);

           //Append the node from the Manifest file to the main DOM

           docXN.SelectSingleNode("/my:myFields/my:group1", this.NamespaceManager).AppendChild(xnNode.InnerXml);

       }

       public void DeleteNil(XPathNavigator node)

       {

           //Check to see if the nil attribute exists

           //and if so, delete it

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

               node.DeleteSelf();

       }

Scott

# February 25, 2009 8:12 AM

spawforths said:

Thanks for that,  I managed to get to work.

When I try and get it to work by altering the code for another form I struggle.

The form I am trying use is a repeatable table that submits to an SQL database.

My 6 fields are

Project

Project_FD

Date_Worked

Work_Code

Work_Description

Here is my altered code, although it fails on

if (xnSortField.Value == ControlID)

public void btnPro_Clicked(object sender, ClickedEventArgs e)

       {

           SpecifySortOptions("Project", XmlDataType.Text, e.ControlId);

       }

       public void SpecifySortOptions(string SortField, XmlDataType dataType, string ControlID)

       {

           //Create Navigator objects for the main DOM and

           //for the SortOrder and SortField fields

           XPathNavigator xn = this.MainDataSource.CreateNavigator();

           XPathNavigator xnSortOrder = xn.SelectSingleNode("/my:myFields/my:SortOrder", this.NamespaceManager);

           XPathNavigator xnSortField = xn.SelectSingleNode("/my:myFields/my:SortField", this.NamespaceManager);

           //Check to see if the value of the SortField is equal

           //to the ControlID that we passed to this procedure. If

           //it is the same and the SortOrder field is an SortOrder

           //emptry string or is set to "Desc" then set the field to

           //"Asc". If the SortField value does not equal the

           //ControlID that we passed to this procedure, then that

           //would mean either the SortField is an empty string or

           //it was set to another field - either way, we will

           //then want the SortOrder value to be "Asc"

           if (xnSortField.Value == ControlID)

           {

               if (xnSortOrder.Value == "" || xnSortOrder.Value == "Desc")

                   xnSortOrder.SetValue("Asc");

               else

                   xnSortOrder.SetValue("Desc");

           }

           else

               xnSortOrder.SetValue("Asc");

           //Call the SortTheData() procedure passing in the values

           //specified above

           SortTheData(SortField, xnSortOrder.Value, dataType);

           //Set the SortField value to the current ControlID

           xnSortField.SetValue(ControlID);

       }

       public void SortTheData(string strSortField, string strSortOrder, XmlDataType dataType)

       {

           //Create a Navigator object for the main DOM

           XPathNavigator xn = this.MainDataSource.CreateNavigator();

           XmlSortOrder sortOrder = XmlSortOrder.Ascending;

           if (strSortOrder == "Desc")

               sortOrder = XmlSortOrder.Descending;

           XPathExpression xe = xn.Compile("/my:myFields/dataFields/d:Project_Hours");

           xe.AddSort("*[local-name()='" + strSortField + "']", sortOrder, XmlCaseOrder.None, "", dataType);

           xe.SetContext(this.NamespaceManager);

           XPathNodeIterator xi = xn.Select(xe);

           XPathNavigator firstNode = xn.SelectSingleNode("/my:myFields/dataFields/d:Project_Hours[1]", this.NamespaceManager);

           XPathNavigator lastNode = xn.SelectSingleNode("/my:myFields/dataFields/d:Project_Hours[" + xi.Count + "]", this.NamespaceManager);

           firstNode.DeleteRange(lastNode);

           while (xi.MoveNext())

           {

               //Create string variables to hold the values of each field

               //as we iterate the nodes

               string strProject = xi.Current.SelectSingleNode("my:Project", this.NamespaceManager).Value;

               string strProject_FD = xi.Current.SelectSingleNode("my:Project_FD", this.NamespaceManager).Value;

               string strDate_Worked = xi.Current.SelectSingleNode("my:Date_Worked", this.NamespaceManager).Value;

               string strWork_Code = xi.Current.SelectSingleNode("my:Work_Code", this.NamespaceManager).Value;

               string strWork_Description = xi.Current.SelectSingleNode("my:Work_Description", this.NamespaceManager).Value;

               string strBillable_Hours = xi.Current.SelectSingleNode("my:Billable_Hours", this.NamespaceManager).Value;

               //Call the AddNewRow method to append a new row

               // to the repeating group

               AddNewRow(xn.SelectSingleNode("/my:myFields/dataFields", this.NamespaceManager));

               //Since we are continually appending new rows, the  

               //"last" row will always be the one where we need

               //to set the values - so here we will create a

               //Navigator object for this newly added row - we

               //will use this for setting the field values below

               XPathNavigator xnNewRow = xn.SelectSingleNode("/my:myFields/dataFields/d:Project_Hours[last()]", this.NamespaceManager);

               xnNewRow.SelectSingleNode("my:Project", this.NamespaceManager).SetValue(strProject);

               xnNewRow.SelectSingleNode("my:Project_FD", this.NamespaceManager).SetValue(strProject_FD);

               xnNewRow.SelectSingleNode("my:Work_Description", this.NamespaceManager).SetValue(strWork_Description);

               //Since the Age field is numeric, it will contain

               //the "nil" attribute. We need to remove this

               //arrtibute prior to programmatically setting the

               //value. To do this, we'll call the DeleteNil

               //procedure passing it the node that contains

               //(or may contain) the nil attribute

               DeleteNil(xnNewRow.SelectSingleNode("my:Date_Worked", this.NamespaceManager));

               DeleteNil(xnNewRow.SelectSingleNode("my:Work_Code", this.NamespaceManager));

               DeleteNil(xnNewRow.SelectSingleNode("my:Billable_Hours", this.NamespaceManager));

               //Now we can set the value of the Age field

               xnNewRow.SelectSingleNode("my:Date_Worked", this.NamespaceManager).SetValue(strDate_Worked);

               xnNewRow.SelectSingleNode("my:Work_Code", this.NamespaceManager).SetValue(strWork_Code);

               xnNewRow.SelectSingleNode("my:Billable_Hours", this.NamespaceManager).SetValue(strBillable_Hours);

           }

       }

       public void AddNewRow(XPathNavigator docXN)

       {

           //Create a Navigator object to reference the node

           //we will be adding. To do this, we can use the

           //templates' "Manifest.xsf" file to get the

           //appropriate node to add. As you can see, this is

           //specific to the control's "name", which you can

           //get from the Advanced tab on the Properties window

           //for the repeating control. Once you have this,

           //use the "Save As Source Files" command from the  

           //File menu in InfoPath and locate the appropriate

           //expression in your Manifest.xsf file

           XPathNavigator xnNode = this.Template.Manifest.SelectSingleNode("//xsf:xDocumentClass/xsf:views/xsf:view/xsf:editing/xsf:xmlToEdit[@name='Project_Hours_1']/xsf:editWith/xsf:fragmentToInsert/xsf:chooseFragment/my:group1", this.NamespaceManager);

           //Append the node from the Manifest file to the main DOM

           docXN.SelectSingleNode("/my:myFields/dataFields", this.NamespaceManager).AppendChild(xnNode.InnerXml);

       }

       public void DeleteNil(XPathNavigator node)

       {

           //Check to see if the nil attribute exists

           //and if so, delete it

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

               node.DeleteSelf();

       }

   }

}

# February 26, 2009 9:40 AM

spawforths said:

The error I receive is

nullReferenceException was unhandled by user code

# February 26, 2009 10:09 AM

infopath said:

Hi spawforths,

It may simply be your XPATH expressions are not correct. For instance, this looks wrong:

XPathExpression xe = xn.Compile("/my:myFields/dataFields/d:Project_Hours");

If you have built your XSN from a data source (i.e. SQL), this would typically be like this:

XPathExpression xe = xn.Compile("/my:myFields/dfs:dataFields/d:Project_Hours");

To be sure of the XPATH expressions you can select the node you want in the Data Source Task Pane, right-click and choose Copy XPath.

I would first verify all your expressions and if it still fails, then you will need to debug (step through) your code to find the exact line that is failing and correct that problem.

Scott

# February 26, 2009 5:32 PM

spawforths said:

Hi Scott,

 Thanks for that,

 I started to change the x-path references, it seems to fail on

vxnNewRow.SelectSingleNode("@Project", this.NamespaceManager).SetValue(strProject);

But it gives me the error: The name ' vxnNewRow' does not exist in the current context.

any idea?

# March 2, 2009 5:07 AM

infopath said:

Hi spawforths,

What this error indicates is the "vxnNewRow" variable is not declared at the correct location. Now, if you are using the sample code I provided, then the variable name should be "xnNewRow" - did you change the variable names? If so, then it sounds like it is not declared at the correct location.

The other thing it could be is when you create that variable, it is done on this line:

XPathNavigator xnNewRow = xn.SelectSingleNode("/my:myFields/dataFields/d:Project_Hours[last()]", this.NamespaceManager);

Maybe in your case, the XPATH expression does not return any rows? If not, when you step through the code and hover your mouse over this variable (after moving past this line) if the "vxnNewRow" variable is "null" then there again is a problem with the expression.

Scott

# March 2, 2009 10:29 AM
Anonymous comments are disabled
Page view tracker