/* LEGAL NOTICE This document supports a preliminary release of a software product that may be changed substantially prior to final commercial release. This document is provided for informational purposes only and Microsoft makes no warranties, either express or implied, in this document. Information in this document, including URL and other Internet Web site references, is subject to change without notice. The entire risk of the use or the results from the use of this document remains with the user. Unless otherwise noted, the companies, organizations, products, domain names, e-mail addresses, logos, people, places, and events depicted in examples herein are fictitious. No association with any real company, organization, product, domain name, e-mail address, logo, person, place, or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation. Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property. © 2006 Microsoft Corporation. All rights reserved. Microsoft and Microsoft Infopath are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries. */ public void btnLastName_Clicked(object sender, ClickedEventArgs e) { //Call the "SpecifySortOptions()" procedure passing it the field //we want to use for sorting (LastName), the data type of this //field (XmlDataType.Text) and the ControlID of this button - //this ControlID is used in the Expression for the Default Value //property of each button to determine how to change the label. SpecifySortOptions("LastName", XmlDataType.Text, e.ControlId); } public void btnFirstName_Clicked(object sender, ClickedEventArgs e) { //Call the "SpecifySortOptions()" procedure passing it the field //we want to use for sorting (FirstName), the data type of this //field (XmlDataType.Text) and the ControlID of this button - //this ControlID is used in the Expression for the Default Value //property of each button to determine how to change the label. SpecifySortOptions("FirstName", XmlDataType.Text, e.ControlId); } public void btnAge_Clicked(object sender, ClickedEventArgs e) { //Call the "SpecifySortOptions()" procedure passing it the field //we want to use for sorting (Age), the data type of this //field (XmlDataType.Number) and the ControlID of this button - //this ControlID is used in the Expression for the Default Value //property of each button to determine how to change the label. SpecifySortOptions("Age", XmlDataType.Number, e.ControlId); } //This procedure is used to set the values of the SortField and SortOrder //fields based on the values passed in from the click event of each //button. Once these field values are set, this procedure calls the //"SortTheData()" procedure passing it the values that we just set. 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 emptry string or is set to "Desc" then set the SortOrder //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 specfied above SortTheData(SortField, xnSortOrder.Value, dataType); //Set the SortField value to the current ControlID xnSortField.SetValue(ControlID); } private void SortTheData(string strSortField, string strSortOrder, XmlDataType dataType) { //Create a Navigator object for the main DOM XPathNavigator xn = this.MainDataSource.CreateNavigator(); //Create a Sort object for specifying whether to sort Asc or Desc - //for this sample, we will use Asc as the default; however we will //need to check the value of strSortOrder passed into this function //and if this is Desc, change the sortOrder object accordingly XmlSortOrder sortOrder = XmlSortOrder.Ascending; if (strSortOrder == "Desc") sortOrder = XmlSortOrder.Descending; //Create an XPath Expression object for the repeating node we want to //sort so we can use the "AddSort" method of the XPathExpression object XPathExpression xe = xn.Compile("/my:myFields/my:group1/my:group2"); //Specify the sort 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); //Add the SetContext method for the XPath Expression object //passing it the NamespaceManager xe.SetContext(this.NamespaceManager); //Create an XPathNodeIterator object, passing it our XPathExpression //object, to walk 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); //Create a Navigator object for the first and last nodes in the //repeating group - These will be used to delete the existing //nodes in the next line of code 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); //Delete the existing nodes using the DeleteRange method firstNode.DeleteRange(lastNode); //Now we are ready to add back the sorted nodes from the //XPathNodeIterator object we created above 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 and 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(); }