Skip navigation

XmlDataSource Enhanced

Add Editing, Deleting, and Inserting Capabilities to Your XmlDataSource Controls

asp:Feature

LANGUAGES: C# | VB.NET

ASP.NET VERSIONS: 2.0

 

XmlDataSource Enhanced

Add Editing, Deleting, and Inserting Capabilities to Your XmlDataSource Controls

 

By Dr. Shahram Khosravi

 

Tabular data-bound controls, such as GridView and DetailsView, expect tabular data from the underlying data store. Hierarchical data-bound controls, on the other hand, such as TreeView and Menu, expect hierarchical data. This causes a big problem in data-driven Web applications where data comes from different sources, such as Microsoft SQL Server, Oracle, Microsoft Access, XML documents, flat files, and Web services, just to name a few.

 

There is no guarantee that the underlying data store will always return tabular data to tabular data-bound controls, or hierarchical data to hierarchical data-bound controls. Let s consider an example. Imagine a GridView control in the Web application of an organization that displays tabular data (e.g. products information) coming from the Microsoft SQL Server database of one of the company s clients. Suppose that the company decides to provide services to a new client where the data comes from XML documents. This could be because either the client stores its products information in XML documents or the client uses XML Web services to expose its products information as XML. Either way, the new client will not return tabular data to the GridView control.

 

The ASP.NET 2.0 data source controls isolate data-bound controls from the underlying data store and present them with the appropriate views of the data store. They present tabular data-bound controls with the tabular views, whether or not the data store is tabular, and hierarchical data-bound controls with the hierarchical views, whether or not the data store is hierarchical.

 

Data source controls that implement the IDataSource interface expose tabular views and those that implement the IHierarchicalDataSource interface expose hierarchical views. The XmlDataSource control is in a unique position because it implements both the IDataSource and IHierarchicalDataSource interfaces. Therefore, it exposes both tabular and hierarchical views of its underlying XML document, allowing both tabular and hierarchical data-bound controls to be bound to it. This article will develop a Web application that uses both tabular and hierarchical views of the XmlDataSource control.

 

The main problem with the XmlDataSource control is that it doesn t provide built-in support for Delete, Update, or Insert data operations. This is a major issue in XML-based Web applications where XML documents are used as a data store. This article shows how we can use the underlying XmlDocument object of the XmlDataSource control to add support for other operations, such as Delete, Insert, and Update.

 

Tree Representation and Location Paths

This article presents the implementation of an XML-based threaded discussion forum, where an XML document is used as its data store. Figure 1 shows part of the XML document.

 

  

   Looking for a good book on ASP.NET

   I'm looking for a book with lot of examples.

  

     Are you looking for a book

     for beginners?

    What kind of book are you looking for?

    

      Books for beginers with lot

       of examples

       I'm looking for a book with lot

       of examples

      

        What sort of examples?

        Could you be more specific?

        

          Examples with practical

           applications

          Code examples that I could use in

           my work

        

     

    

    

  

    New ASP.NET books are coming out

    You may want to check out amazon.com for new

     books on ASP.NET

    

      Thanks, I will

      I will check out amazon.com. I may get

       lucky there.

   

   

  

   Any one have code examples for data

  source controls

 I need code examples that show how to use data

  source controls in big applications

  

   What type of data source controls?

   There are all kinds of data source controls.

   Which ones are you planning on using?

  

 

Figure 1: The messages.xml file.

 

A element represents a posted message where the and child elements contain the subject and body of the message, respectively. The AddedDate and UserName attributes of a given element represent the date the message was posted and the user name of the author, respectively.

 

The XmlDataSource control must first load the document into memory. In general, there are two loading models: streaming and DOM (Document Object Model). The streaming model reads in the XML document as a stream of nodes where only the current node is kept in memory. The XmlDataSource control uses the W3C DOM model to load the entire contents of the messages.xml file into an instance of the XmlDocument class and generate the in-memory tree representation of the document, as shown in Figure 2.

 


Figure 2: The in-memory tree representation of the messages.xml file.

 

Let s compare the XmlDataSource and SqlDataSource loading models. The SqlDataSource control loads the underlying database tables into an instance of the DataSet class and generates the in-memory tabular representation of the underlying tables. The in-memory tabular representation consists of interconnected rows where each row is an instance of the DataRow class.

 

Now compare that with the in-memory tree representation, such as shown in Figure 2, which consists of interconnected nodes where each node is an instance of the XmlNode class. The XmlNode class is an abstract class that represents any type of node. Each of its subclasses represents a particular type of node. For instance, the XmlElement subclass represents element nodes, i.e. , , and ; the XmlAttribute subclass represents attribute nodes, i.e. AddedDate and UserName.

 

When we select, delete, insert, or update a row in a DataSet object, we don t directly select, delete, insert, or update the corresponding row in the underlying database table, because the DataSet object is not connected to the database. In other words we select, delete, insert, or update the row in the in-memory tabular representation of the database table, not the database table itself. This is why the changes to the in-memory tabular representation must be explicitly committed to the underlying database tables.

 

The same argument applies to the XmlDocument object that has been loaded with the data from the underlying messages.xml file. When we select, delete, insert, or update a node in the XmlDocument object, we don t directly select, delete, insert, or update the corresponding node in the underlying XML document, because the XmlDocument object isn t connected to the XML document itself. In other words, we select, delete, insert, or update the node in the in-memory tree representation of the XML document, not the document itself. This is why the changes to the in-memory tree representation must be explicitly committed to the underlying XML document.

 

To modify a row or node in the underlying data store we must first modify the row or node in the corresponding tabular or tree representation, then commit the changes. Because a tabular or tree representation is a collection of rows or nodes, we cannot work with a row or node in the collection until we first locate and identify that row or node in the collection.

 

Page developers use the primary key of a row to uniquely locate and identify the row in the underlying tabular representation. The primary key of a row plays a crucial role in data operations, such as select, delete, update, and insert, because without it there is no way to know which row is being modified or selected. The XPath data model uses a concept known as hierarchical or location path to uniquely locate or identify a node in the tree hierarchy. The hierarchical or location paths play the same role in a tree hierarchy that primary keys play in a tabular representation.

 

As Figure 2 shows, every node in the tree is the root node of yet another tree unless the node is a leaf node. This means the tree is a hierarchy of trees where each tree is built out of smaller trees. The path of a node in a tree hierarchy uniquely identifies and locates not only the node itself but also the sub tree associated with the node.

 

The primary key of a row is normally an autogenerated integer number with a unique value. The hierarchical or location path of a node, on the other hand, is built out of the location steps of its ancestor nodes all the way up to the root node of the entire tree hierarchy. The hierarchical path of a node is based on an imaginary journey from the root node of the tree all the way down to the node itself. The journey consists of several location steps. Each location step takes us from the node where we are currently to the next node. Let s consider an example: Suppose we want to locate the gray node (Message) shown in Figure 2.

 

Our journey begins at the root node of the entire tree hierarchy. The XPath data model uses the notation / to represent the root node. The first location step:

 

Messages[position=1]

 

takes us from the root node to the Messages node. So far the location path is:

 

/Messages[position=1]

 

The second location step:

 

Message[position=1]

 

takes us from the Messages node to the first Message node. The location path is so far then:

 

/Messages[position=1]/Message[position=1]

 

The third location step:

 

Message[position=1]

 

takes us from the current Message node to the next Message node. The location path is now:

 

/Messages[position=1]/Message[position=_

 1]/Message[position=1]

 

The final location step:

 

Message[position=1]

 

takes us to our destination, i.e. the gray node. Therefore, the location path of the gray node is as follows:

 

/Messages[position()=1]/Message[position()=_

 1]/Message[position()=1]/Message[position()=1]

 

As the example shows, the location path of a node uniquely identifies and locates the node and its associated sub tree in the tree hierarchy.

 

The XmlDataSource control provides hierarchical data-bound controls such as TreeView and Menu with the hierarchical views of the underlying XML document. A hierarchical view represents a particular sub tree in the in-memory tree representation of the document. Therefore, the hierarchical path of the root node of a sub tree uniquely identifies the hierarchical view that represents the sub tree. That is why the hierarchical path of the root node of a sub tree is also referred to as a view path. Every hierarchical view has a unique view path.

 

To make our discussion more concrete, let s examine the user interface of the threaded discussion forum application more closely, as shown in Figure 3.

 


Figure 3: The XML-based threaded discussion forum.

 

The user interface consists of a TreeView and a DetailsView control. The TreeView control displays the subject, added date, and user name of all the message nodes of the tree hierarchy. The TreeView and DetailsView controls create a master/detail form where the user selects a message from the TreeView control to see its details in the DetailsView control. The DetailsView control also allows authorized users to edit, delete, or reply to the selected message or start a new thread of discussion.

 

The DetailsView control, therefore, does not display, edit, delete, or reply to all the message nodes of the tree. It only displays, edits, deletes, or replies to the message node that the user selected from the TreeView control. This means the DetailsView control must first locate the selected message node in the underlying tree representation. The only way to locate a node in a tree is to find out its hierarchical or location path. Let s see how the DetailsView control accesses the hierarchical path of the selected message.

 

The TreeView control creates an instance of the TreeNode class for each message node it displays and sets its DataPath property to the hierarchical or location path of the message node. When the user selects a message from the TreeView control, the SelectedNode property of the control is set to the TreeNode object that represents the selected message node. Therefore the DetailsView control can easily use the DataPath property of the SelectedNode object of the TreeView control to access the hierarchical path of the selected message node, i.e. TreeView1.SelectedNode.DataPath.

 

One of the responsibilities of the DetailsView control is to use the hierarchical path of the selected message node to locate the node in the underlying tree representation, extract its details, and display them to users. Thanks to the new ASP.NET 2.0 data source and data-bound model, this is all done automatically. All a page developer needs to do is to set the XPath property of the XmlDataSource associated with the DetailsView control to the hierarchical path of the selected message node. This can easily be done in the callback for the SelectedNodeChanged event of the TreeView control:

 

void SelectedNodeChanged(object sender, EventArgs e)

{

 MySource2.XPath = TreeView1.SelectedNode.DataPath;

 if (dv.CurrentMode != DetailsViewMode.ReadOnly)

   dv.ChangeMode(DetailsViewMode.ReadOnly);

}

 

Setting the XPath property of the XmlDataSource control associated with the DetailsView control (i.e. MySource2) to the hierarchical path of the selected message node is all it takes to have the DetailsView control extract the details of the selected message node from the tree and display them. Let s see what makes this possible.

 

The DetailsView control internally registers a callback for the DataSourceChanged event of its associated XmlDataSource control, i.e. MySource2. The XmlDataSource control raises the event when:

1)     One or more of its properties change value.

2)     The underlying data store changes because of a Delete, Update, or Insert operation.

 

Therefore, setting the XPath property of the XmlDataSource control raises the DataSourceChanged event and calls the internal callback function where the DetailsView control uses the XmlDataSource control to automatically extract the details of the selected message node from the underlying tree and displays them to users.

 

The great thing about the DetailsView control is that it allows all operations, i.e. display, edit, delete, and reply, and adds a new thread to be handled within the same server control, i.e. the DetailsView control. Switching from one operation to another is done via switching the mode of the DetailsView control. The DetailsView control can be in one of the three possible modes, i.e. DetailsViewMode.ReadOnly, DetailsViewMode.Edit, and DetailsViewMode.Insert.

 

When the user selects a message from the TreeView control, the DetailsView control is switched to the DetailsViewMode.ReadOnly mode where the details of the selected message are displayed. When the user clicks the Edit button of the DetailsView control, the DetailsView control is switched to the DetailsViewMode.Edit mode, where the user can edit the selected message. When the user clicks the Reply button of the DetailsView control, the DetailsView control is switched to the DetailsViewMode.Insert mode, where the user can reply to the selected message. When the user clicks the NewThread button, the DetailsView control is switched to the DetailsViewMode.Insert mode, where the user can start a new thread.

 

Displaying All Messages

The TreeView control uses the following XmlDataSource control to extract all the message nodes from the tree:

 

 EnableCaching="true"  CacheDuration="300"

 CacheExpirationPolicy="Sliding" CacheKeyDependency="MyKey"

 DataFile="messages.xml" XPath="/Messages/Message" />

 

The XPath property operates like the SelectCommand of the SqlDataSource control, i.e. it specifies which message nodes will be selected. In this case, it s set to the value /Messages/Message to extract all the message nodes.

 

Accessing the underlying data store is one of the most time-consuming operations in data-driven Web applications. Page developers normally cache data query results in the Cache object to improve the performance. The XmlDataSource control allows page developers to cache data without writing a single line of code. All they have to do is set the EnableCaching, CacheDuration, and CacheExpirationPolicy properties of the XmlDataSource control. The possible values of CacheExpirationPolicy are Sliding and Absolute.

 

Automatic caching is possible because the XmlDataSource control uses W3C DOM APIs to load the entire XML document into memory. The streaming load model, on the other hand, does not allow caching because only the current node is kept in memory.

 

The downside of caching is the problem of stale data. This problem occurs when the underlying data store changes but the application still displays out of date information. Like any other ASP.NET component, the XmlDataSource control uses the Insert method of the Cache object to cache the query results. The Insert method takes three arguments. The first argument specifies the key under which the data is cached. The key is later used to access the cached data. The XmlDataSource control exposes a public property named CacheKeyDependency. The control caches the data under the key that page developers specify as the value of this property.

 

We ll see later that the callbacks for the Delete, Update, and Edit operations in the DetailsView control call the Remove method of the Cache object to invalidate the data cached under the key specified in the CacheKeyDependency property. The next time the page is accessed the XmlDataSource control will extract fresh data from the underlying XML document. This automatically resolves the problem of stale data.

 

The application also registers the DataBound method as the callback for the TreeNodeDataBound event of the TreeView control, where it specifies what information to display for each message:

 

void DataBound(Object sender, TreeNodeEventArgs e)

{

 if (((XmlNode)e.Node.DataItem).LocalName == "Message")

 e.Node.Text = XPathBinder.Eval(e.Node.DataItem,

  "Subject").ToString() + ", by " +

  XPathBinder.Eval(e.Node.DataItem, "@UserName").ToString() +

  "   " + XPathBinder.Eval(e.Node.DataItem,

  "@AddedDate").ToString();

}

 

The Eval method of the XPathBinder takes two arguments. The first argument is the object against which a given XPath expression is evaluated. The second argument is the XPath expression being evaluated. The first argument only accepts objects whose classes implement the IXPathNavigable interface. This is because the Eval method simply calls the CreateNavigator method of the object to access its XPathNavigator object. The Eval method then calls the Select method of the XPathNavigator object and passes the XPath expression as its argument.

 

Let s take a look at the XPath expressions used as the second arguments of the Eval method calls, i.e. Subject, @UserName, and @AddedDate. These expressions refer to the child element and UserName and AddedDate attributes of the selected message node. As shown in Figure 2, the child element and UserName and AddedDate attributes are themselves nodes of the tree hierarchy. Therefore, the XPath expressions are nothing but the location steps that take us from the selected message node to the Subject, UserName, and AddedDate nodes. The Select method of the XPathNavigator object uses these location steps to locate these nodes and return references to them.

 

Displaying the Details of a Message

Because the DetailsView control is bound to an XmlDataSource control where every data item implements the IXPathNavigable interface, it uses XPathBinder in its data-binding expressions. XPath is the short version of XPathBinder.Eval(Container.DataItem, xpathexpression, format). The DetailsView control uses four XPath data-binding expressions:

1)     XPath( Subject/text ) returns the subject of the selected message node. The text function returns the text within the opening and closing tags of the element in the XML document. As Figure 2 shows, the text itself is a node in the tree hierarchy. The XPath expression Subject/text is therefore a location path that takes us from the selected message node to the text node.

2)     XPath ( Body/text ) returns the body of the selected message node.

3)     XPath ( @AddedDate ) returns the value of the AddedDate attribute of the selected element. As Figure 2 shows, the attribute itself is a node.

4)     XPath ( @UserName ) returns the value of the UserName attribute of the selected element.

 

The DetailsView control and its associated XmlDataSource control work together to automatically display the details of the message node that the user selects from the TreeView control. In other words, the select operation is done automatically. However, XmlDataSource does not provide automatic support for delete, update, and insert operations; the application must explicitly handle these operations.

 

Deleting a Message

The ItemTemplate section of the DetailsView control contains the delete button. The DetailsView control provides built-in support for deleting items. Page developers only need to add a new delete button to the ItemTemplate section and set its CommandName property to Delete . When the user clicks the Delete button, the DetailsView control checks the value of the CanDelete property of its associated view object. If it is true, the control calls the Delete method of the view object; otherwise, it throws an exception. The CanDelete property value is true only when the view object implements the Delete method.

 

However, the XmlDataSourceView class does not implement the Delete method. Therefore, the application must not set the CommandName property of the delete button to the value Delete , otherwise an exception would be thrown when the button is clicked. The application sets the CommandName property of the delete button to the value SubmitDelete instead and registers the DetailsView_ItemCommand method as the callback for the ItemCommand event of the DetailsView control to handle the delete event. Later, we ll see that the DetailsView_ItemCommand method will also be used to handle the update and insert events:

 

void DetailsView_ItemCommand(object sender,

                             DetailsViewCommandEventArgs e)

{

 switch (e.CommandName)

 {

   case "SubmitUpdate":

     Update();

     break;

   case "SubmitInsert":

     Insert();

     break;

   case "SubmitDelete":

     Delete();

     break;

 }

}

 

The method calls the Delete method to handle the delete event:

 

void Delete()

{

 XmlDocument doc = MySource2.GetXmlDocument();

 String dataPath = TreeView1.SelectedNode.DataPath;

 XmlNode message = doc.SelectSingleNode(dataPath);

 message.ParentNode.RemoveChild(message);

 MySource2.XPath = "";

 Save();

}

 

As previously discussed, the XmlDataSource control uses the W3C DOM APIs to load the entire messages.xml file into memory, and creates an in-memory tree representation of the XML document. The great thing about the W3C DOM model is that it allows page developers to add, update, and delete nodes from the in-memory tree. The XmlDataSource control exposes a method named GetXmlDocument that returns a reference to the underlying XmlDocument object.

 

Deleting a node from the tree hierarchy involves the following four steps:

1)     Find out the hierarchical path of the node to be deleted. Because the message node being deleted is the node that the user selected from the TreeView control, the value of the DataPath property of the SelectedNode of the TreeView control is the hierarchical path of the node being deleted.

2)     Call the SelectSingleNode method of the XmlDocument object and pass the hierarchical path of the node as its argument. The method uses the hierarchical path to locate the message node in the tree XmlNode message = doc.SelectSingleNode(TreeView1.Selected.DataPath);

3)     Access the parent node of the node being deleted, XmlNode parent = message.ParentNode;

4)     Call the RemoveChild method of the parent node to delete the node from the tree, parent.RemoveChild(message);

 

The Delete method then calls the Save method:

 

 void Save()

{

 MySource2.Save();

 if (DetailsView1.CurrentMode != DetailsViewMode.ReadOnly)

   DetailsView1.ChangeMode(DetailsViewMode.ReadOnly);

 Cache.Remove("MyKey");

 TreeView1.DataBind();

}

 

The Save method takes care of the following issues:

1)     Removing the selected message node from the in-memory tree hierarchy does not automatically remove the message from the underlying data store, i.e. XML document. The Save method calls the Save method of the associated XmlDataSource control to propagate the changes to the XML document.

2)     Recall the XmlDataSource control associated with the TreeView control caches its query results in the Cache object under the key specified in its CacheKeyDependency property. Because the Delete method changes the underlying data store, it must call the Remove method of the Cache object to invalidate the cached data; otherwise, the TreeView control will show out of date data.

3)     The DataBind method of the TreeView control must be called to update the TreeView control display. Because the cached data has already been invalidated, the DataBind method will extract fresh data from the underlying XML document.

4)     The DetailsView control must be switched back to its ReadOnly mode.

 

Updating a Message

The ItemTemplate section of the DetailsView control contains the edit button. Because the CommandName property of the button is set to Edit , when the user clicks the button, the DetailsView control automatically switches to DetailsViewMode.Edit mode where it renders the contents of its EditItemTemplate section including the Update and Cancel buttons.

 

When the Cancel button is clicked, the DetailsView control automatically switches back to the DetailsViewMode.ReadOnly mode where it renders the contents of its ItemTemplate section. Notice the CommandName property of the Update button is not set to Update for the same reason that the CommandName property of the Delete button was not set to Delete . The application sets the property to SubmitUpdate and uses the DetailsView_ItemCommand method to handle the event. The method calls the Update method to handle the Update event (see Figure 4).

 

void Update()

{

 TextBox subject1 = (TextBox)DetailsView1.FindControl("EditSubject");

 TextBox body1 = (TextBox)DetailsView1.FindControl("EditBody");

 XmlDocument doc = MySource2.GetXmlDocument();

 string subjectPath = TreeView1.SelectedNode.DataPath + "/Subject";

 XmlNode subject = doc.SelectSingleNode(subjectPath);

 subject.InnerText = subject1.Text;

 string bodyPath = TreeView1.SelectedNode.DataPath + "/Body";

 XmlNode body = doc.SelectSingleNode(bodyPath );

 body.InnerText = body1.Text;

 Save();

}

Figure 4: The DetailsView_ItemCommand method calls the Update method to handle the Update event.

 

The Update method first extracts the new values for the subject and body of the selected message. To update a node in the tree hierarchy, first find out the hierarchical path of the node to be updated. Because the message node being updated is the message that the user selected from the TreeView control, the value of the DataPath property of the SelectedNode of the TreeView control is the hierarchical path of the message node. However, we want to update the child nodes (i.e. subject and body nodes) of the message node, not the message node itself. Recall the hierarchical path of a node takes us from the root node of the tree, node by node, all the way down to the node itself. The hierarchical path consists of location steps where each location step takes us from the node where we are currently to the next node. This means we need to add another location step to the hierarchical path of the message node to go from the message node to its child nodes, i.e. subject and body nodes. Therefore the hierarchical paths of the subject and body nodes are:

 

string subjectPath = TreeView1.SelectedNode.DataPath +

 "/Subject";

sring bodyPath = TreeView1.SelectedNode.DataPath + "/Body";

 

Next, call the SelectSingleNode method of the XmlDocument object and pass the hierarchical path of the node to access the node in the tree:

 

XmlNode subject = doc.SelectSingleNode(subjectPath);

XmlNode body = doc.SelectSingleNode(bodyPath);

 

Then update the node:

 

subject.InnerText = subject1.Text;

body.InnerText = body1.Text;

 

Notice the SelectSingleNode method returns the reference to the actual node in the tree. This allows us to directly update the properties of the subject and body nodes. At the end, the Update method does exactly what the Delete method did; that is, it calls the Save method.

 

Replying to a Message

The ItemTemplate property of the DetailsView control contains the Reply button. Because the CommandName property of the button is set to New, when the user clicks the button, the DetailsView control automatically switches to the DetailsViewMode.Insert mode where the control renders the contents of its InsertItemTemplate section that also includes the Insert button.

 

Notice the CommandName property of the Insert button is not set to Insert for the same reason that the CommandName properties of the Delete and Update buttons were not set to Delete and Update . The application sets the property to SubmitInsert and uses the DetailsView_ItemCommand method to handle the event. The method calls the Insert method to handle the Insert event. Figure 5 shows the code for the Insert method.

 

void Insert()

{

 TextBox subject1 = (TextBox)DetailsView1.FindControl("InsertSubject");

 TextBox body1 = (TextBox)DetailsView1.FindControl("InsertBody");

 XmlDocument doc = MySource2.GetXmlDocument();

 XmlElement message = doc.CreateElement("Message");

 XmlNode parent;

 if (ViewState["NewThread"] == null)

     parent = doc.SelectSingleNode(TreeView1.SelectedNode.DataPath);

 else

 {

     ViewState.Remove("NewThread");

     parent = doc.DocumentElement;

 }

 parent.AppendChild(message);

 message.SetAttribute("AddedDate", DateTime.Now.ToShortDateString());

 message.SetAttribute("UserName", User.Identity.Name);

 XmlElement subject = doc.CreateElement("Subject");

 message.AppendChild(subject);

 subject.InnerText = subject1.Text;

 XmlElement body = doc.CreateElement("Body");

 message.AppendChild(body);

 body.InnerText = body1.Text;

 Save();

}

Figure 5: The Insert method is used to reply to the selected message or start a new thread.

 

Adding a new element node to the tree hierarchy involves the following six steps:

1)     Call the CreateElement method of the XmlDocument object to create the new element node.

2)     Set the properties of the new element node.

3)     Call the SetAttribute method of the new element node to set its attributes.

4)     Find out the hierarchical path of the element node that will act as the parent node of the new element node.

5)     Call the SelectSingleNode method of the XmlDocument object and pass the hierarchical path of the parent node as its argument to access the parent node in the tree.

6)     Call the AppendChild method of the parent node to add the new element node to the tree as its child node.

 

The Insert method creates three element nodes and adds them to the tree hierarchy. The first element node represents the reply message itself. The second and third element nodes represent the subject and body of the reply message. The Insert method follows the previously mentioned six steps for each element node that it creates and adds to the tree hierarchy. For instance, let s consider the six steps for the creation and addition of the element node that represents the reply message itself:

1)     Create the element node, XmlElement message = doc.CreateElement( Message );

2)     Not applicable

3)     Because the message element exposes two attributes, we must call the SetAttribute method twice: message.SetAttribute( AddedDate , DateTime.Now.ToShortDateString); and message.SetAttribute( UserName , User.Identity.Name);

4)     Because the message node being added is the reply to the message node that the user selected from the TreeView control, the selected message node will be the parent of the new message node. Therefore, the value of the DataPath property of the SelectedNode of the TreeView control is the hierarchical path of the parent node of the new element node.

5)     Access the parent element node in the tree hierarchy, XmlNode parent = doc.SelectSingleNode(TreeView1.SelectedNode.DataPath);

6)     Add the new element node to the tree hierarchy as the child node of the parent node, parent.AppendChild(message);

 

At the end, the Insert method calls the Save method to commit all the changes to the disk and update the TreeView and DetailsView controls.

 

Starting a New Thread

The NewThreadClick method is registered as the callback for the Click event of the NewThread button:

 

void NewThreadClick(object sender, EventArgs e)

{

 DetailsView1.ChangeMode(DetailsViewMode.Insert);

 ViewState["NewThread"] = "NewThread";

}

 

The method calls the ChangeMode method of the DetailsView control to change its mode to DetailsViewMode.Insert where the control renders the contents of its InsertItemTemplate property. The method also stores NewThread in ViewState under the key NewThread .

 

Because both replying to a message and creating a new thread switch the DetailsView control to its Insert mode, the same discussions presented in the previous section apply equally to this section. The only difference is that the Insert method appends the newly created message node as the child node of the document element because it starts a new thread. The Insert method uses ViewState[ NewThread ] as the signal to find out whether the user is starting a new thread or replying to an existing message.

 

Conclusion

This article presents the implementation of an XML-based threaded discussion forum that uses new ASP.NET 2.0 controls such as XmlDataSource, TreeView, and DetailsView and an XML document as its data store. The TreeView and DetailsView controls create master/detail views of messages. Selecting a message from the TreeView control displays its details in the DetailsView control where the user can also update, delete, and reply to the message or start a new thread.

 

The XmlDataSource control does not provide built-in support for Update, Delete, and Insert data operations. This article demonstrates how to use the underlying XmlDocument object and the classes in the System.Xml namespace to handle Update, Delete, and Insert operations.

 

This article uses the XPath location path of a message node as its unique identifier. The unique identifiers are used in Update, Delete, or Reply operations to identify the message node being updated, deleted, or replied to.

 

The sample code accompanying this article is available for download.

 

Dr. Shahram Khosravi is a Senior Software Engineer with Schlumberger Information Solutions (SIS). Shahram specializes in ASP.NET 1.x/2.0, XML Web services, .NET 1.x/2.0 technologies, XML technologies, ADO.NET 1.x/2.0, 3D Computer Graphics, HI/Usability, and Design Patterns. Shahram has extensive expertise in developing ASP.NET 1.x/2.0 custom server controls and components. He has more than 10 years of experience in object-oriented programming. He uses a variety of Microsoft tools and technologies such as SQL Server 2000 and 2005. Shahram has written articles on .NET 1.x/2.0 and ASP.NET 1.x/2.0 technologies for asp.netPRO magazine, Microsoft MSDN Online, and CoDe magazine. Reach him at mailto:[email protected].

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish