About

I'm Mike Pope. I live in the Seattle area. I've been a technical writer and editor for over 35 years. I'm interested in software, language, music, movies, books, motorcycles, travel, and ... well, lots of stuff.

Read more ...

Blog Search


(Supports AND)

Feed

Subscribe to the RSS feed for this blog.

See this post for info on full versus truncated feeds.

Quote

The whole integrity of editing rests on the editor's ability, when challenged, to give a reasonable and persuasive explanation for every change in the text—and that disagreements over judgments can be worked out collegially, in discussion.

John McIntyre



Navigation





<January 2025>
SMTWTFS
2930311234
567891011
12131415161718
19202122232425
2627282930311
2345678

Categories

  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  

Contact Me

Email me

Blog Statistics

Dates
First entry - 6/27/2003
Most recent entry - 9/4/2024

Totals
Posts - 2655
Comments - 2677
Hits - 2,721,353

Averages
Entries/day - 0.34
Comments/entry - 1.01
Hits/day - 346

Updated every 30 minutes. Last: 11:48 AM Pacific


  08:14 PM

Last time I played around with updating an XML file using an XmlDataSource control, a GridView control, and a DetailsView control. Inserting into an XML file is similar, in that guess what, you get to do all the work. One decision I made was to have a button on the page that would explictly put the DetailsView control into insert mode. My use of the DetailsView control is therefore maybe not exactly as it might have been designed:
  • Before any row in the GridView control is selected, the DetailsView control is invisible.
  • When you select a row in the GridView control, I make the DetailsView control visible, but also put it into edit mode. When you update the selected row, I disappear the DetailsView control again.
  • To insert a new record, I click a button, which displays the DetailsView control in insert mode. When I click Save, the DetailsView control disappears again.
Make sense? IOW, I'm programmatically controlling the mode in which the DetailsView control appears, rather than using any built-in functionality for that. And I'm really only displaying it in two modes, edit and insert.

Here's the code to put the DetailsView control into insert mode:
Protected Sub buttonInsert_Click(ByVal sender As Object, _
ByVal e As System.EventArgs)
XmlDataSource2.Data = "" ' Clear old data from control
DetailsView1.DataBind()
DetailsView1.Visible = True
DetailsView1.ChangeMode(DetailsViewMode.Insert)
End Sub
If I don't set the Data property (or do something like that), the DetailsView control shows up with whatever record was last edited or inserted.

When you click the Update button, here's what happens:
Protected Sub DetailsView1_ItemInserting(ByVal sender As Object, _
ByVal e As System.Web.UI.WebControls.DetailsViewInsertEventArgs)
Dim newQuote As String = e.Values(0)
Dim newAuthor As String = e.Values(1)


Dim quotesXmlDoc As New System.Xml.XmlDocument
Dim xmlFileName As String = XmlDataSource2.DataFile
xmlFileName = xmlFileName.Replace("~", Server.MapPath("~"))
xmlFileName = xmlFileName.Replace("/", "\")
quotesXmlDoc.Load(xmlFileName)
If quotesXmlDoc Is Nothing Then
Response.Write("Xml doc is nothing")
Exit Sub
End If


' Count #/existing nodes to set new key
Dim lastElement As XmlElement = quotesXmlDoc.DocumentElement.LastChild
Dim newQuoteID As Integer = CInt(lastElement("quoteId").InnerText) + 1


' Create new Quotation element and add children elements to it
Dim newQuoteElement As XmlElement = quotesXmlDoc.CreateElement("Quotation")


Dim quoteIdElement As XmlElement = quotesXmlDoc.CreateElement("quoteId")
quoteIdElement.InnerText = newQuoteID.ToString()
newQuoteElement.AppendChild(quoteIdElement)


Dim quoteElement As XmlElement = quotesXmlDoc.CreateElement("quote")
quoteElement.InnerText = newQuote
newQuoteElement.AppendChild(quoteElement)


Dim authorElement As XmlElement = quotesXmlDoc.CreateElement("author")
authorElement.InnerText = newAuthor
newQuoteElement.AppendChild(authorElement)


quotesXmlDoc.DocumentElement.AppendChild(newQuoteElement)
' Write out updated file
quotesXmlDoc.Save(xmlFileName)


e.Cancel = True


DetailsView1.ChangeMode(DetailsViewMode.ReadOnly)
DetailsView1.Visible = False
End Sub
It's similar to updating, with a couple of small differences. (Other than the obvious difference that I'm adding a new element rather than updating an existing one.) One difference is that I have to come up with a new quoteId value -- that is, a unique key for the new quotation. I use the somewhat cheesy approach of reading the ID value of the last quote in the file and then incrementing that. The assumption, of course, is that the quotes are all in numeric order. That happens to be true in this file, but is hardly a robust algorithm for general use.

This time I got the path of the XML file from the XmlDataSource control and fixed it up by subbing Server.MapPath("~") for the ~ returned as part of the property string. Again, this is because the various System.Xml methods don't know what ~ means.

After writing out the XML file, I cancel the insert method, else the XmlDataSource control throws a not-supported exception, because it doesn't support any update methods.

To complete the triptych of update operations, I added code to be able to delete a quotation. (This has proved handy primarily for deleting the various test quotes I put in there.) I don't need the DetailsView control to delete; I can do that directly from the GridView control by adding a CommandField to the GridView control like this:
<asp:CommandField ShowDeleteButton="True" />
To actually delete the quotation, I used this code:
Protected Sub GridView1_RowDeleting(ByVal sender As Object, _
ByVal e As System.Web.UI.WebControls.GridViewDeleteEventArgs)
XmlDataSource2.Data = "" ' Clear old data from control
DetailsView1.DataBind()
DetailsView1.Visible = False


Dim quoteId As String = e.Keys(0).ToString
Dim quotesXmlDoc As New System.Xml.XmlDocument
Dim xmlFileName As String = XmlDataSource2.DataFile
xmlFileName = xmlFileName.Replace("~", Server.MapPath("~"))
xmlFileName = xmlFileName.Replace("/", "\")
quotesXmlDoc.Load(xmlFileName)


Dim quoteNode As XmlElement
quoteNode = quotesXmlDoc.DocumentElement.SelectSingleNode( _
String.Format("//Quotation[quoteId='{0}']", quoteId))
quotesXmlDoc.DocumentElement.RemoveChild(quoteNode)
quotesXmlDoc.Save(xmlFileName)


GridView1.DataBind()
e.Cancel = True
End Sub
Much like updating -- get key, read XML file, locate node using an XPath expression. This time, call RemoveChild, and poof, it's gone.

I am having one odd problem that I haven't quite resolved. When I update a quote or insert a new one, I call DataBind to refresh the display in the GridView control, and that works great. However, when I do the same thing after deleting a record, the deleted record stubbornly stays visible. If I page away from that page and page back, all is well. So there's something I'm not understanding about re-display after a delete in the GridView contol. When I have that one sussed out, I'll note something here.

One more thing. When I insert a new record, it's always added to the end of the XML file. I decided early on that it would be handy therefore to have a link in the pager that would take me directly to the last page, no matter where I was otherwise. Wow, this turned out to be harder to figure out than I thought it would be. I'll make a separate entry for that, since this is long enough.

[categories]   ,

[9] |