Inserting rows in dataset bound to XmlDataDocument - Framework bug?

T

Troy McLure

I have a C# Windows form with a datagrid. The datagrid displays a
dataset. The dataset is created by reading an xml file. The dataset is
read into an XmlDataDocument. The datagrid and the xml data will not
sync when inserting new rows:

When I insert a new row to the dataset by using
System.Data.DataRowCollection.InsertAt, everything looks fine in the
datagrid. The problem is the xml in the XmlDataDocument. The data is
always inserted at the end of the document and one level too high in the
tree.

If I insert a new row by using XmlElement.InsertAfter, the xml in the
XmlDataDocument looks ok. But the new row always appears at the bottom
of the datagrid!

Any tips would be greatly appreciated!



proj.xml:

<?xml version="1.0" encoding="utf-8"?>
<webmapproject xmlns="http://tempuri.org/webmapproject.xsd">
<legendentries>
<legendentry>
<title>First title</title>
</legendentry>
<legendentry>
<title>Second title</title>
</legendentry>
<legendentry>
<title>Third title</title>
</legendentry>
<legendentry>
<title>Fourth title</title>
</legendentry>
</legendentries>
</webmapproject>



Form1.cs:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Xml;

namespace DataGridInsertion
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Xml.XmlDataDocument gXmlDoc;

private System.Windows.Forms.DataGrid dataGrid1;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button button3;

/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

string xmlFile = Application.StartupPath + "\\..\\..\\proj.xml";
try {
DataSet ds = new DataSet();
ds.ReadXml(xmlFile);
ds.EnforceConstraints=false;

gXmlDoc = new System.Xml.XmlDataDocument(ds);
dataGrid1.DataSource = ds;
this.dataGrid1.DataMember = "legendentry";

}
catch (Exception ex) {
MessageBox.Show(ex.ToString());
}
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.dataGrid1 = new System.Windows.Forms.DataGrid();
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.button3 = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.dataGrid1)).BeginInit();
this.SuspendLayout();
//
// dataGrid1
//
this.dataGrid1.DataMember = "";
this.dataGrid1.HeaderForeColor = System.Drawing.SystemColors.ControlText;
this.dataGrid1.Location = new System.Drawing.Point(8, 48);
this.dataGrid1.Name = "dataGrid1";
this.dataGrid1.Size = new System.Drawing.Size(472, 352);
this.dataGrid1.TabIndex = 0;
//
// button1
//
this.button1.Location = new System.Drawing.Point(192, 16);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(216, 24);
this.button1.TabIndex = 1;
this.button1.Text = "Move 0->2 using XmlElement.InsertAfter";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button2
//
this.button2.Location = new System.Drawing.Point(416, 16);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(64, 24);
this.button2.TabIndex = 2;
this.button2.Text = "Save as...";
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// button3
//
this.button3.Location = new System.Drawing.Point(8, 16);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(176, 24);
this.button3.TabIndex = 3;
this.button3.Text = "Move 0->2 using Rows.insertAt";
this.button3.Click += new System.EventHandler(this.button3_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(496, 406);
this.Controls.Add(this.button3);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Controls.Add(this.dataGrid1);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.dataGrid1)).EndInit();
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

//Using XmlElement.InsertAfter
private void button1_Click(object sender, System.EventArgs e) {
int insertIndex = 1;

System.Data.DataRowCollection rowColl =
gXmlDoc.DataSet.Tables["legendentry"].Rows;

XmlElement firstXmlElement = gXmlDoc.GetElementFromRow(rowColl[0]);
XmlElement parentXmlElement = (XmlElement)firstXmlElement.ParentNode;

//Insert a copy of the first row
XmlElement targetXmlElement =
gXmlDoc.GetElementFromRow(rowColl[insertIndex]);
XmlElement clonedXmlElement =
(XmlElement)firstXmlElement.CloneNode(true);
parentXmlElement.InsertAfter(clonedXmlElement, targetXmlElement);
gXmlDoc.DataSet.AcceptChanges();

//Remove the first row
firstXmlElement = gXmlDoc.GetElementFromRow(rowColl[0]);
parentXmlElement.RemoveChild(firstXmlElement);
gXmlDoc.DataSet.AcceptChanges();
}

//Using Rows.InsertAt:
private void button3_Click(object sender, System.EventArgs e) {
System.Data.DataRowCollection rowColl =
gXmlDoc.DataSet.Tables["legendentry"].Rows;

//Copy data from first row into a new one.
DataRow newRow = gXmlDoc.DataSet.Tables["legendentry"].NewRow();
newRow["title"] = rowColl[0]["title"];
rowColl.InsertAt(newRow,2);
gXmlDoc.DataSet.AcceptChanges();

//Delete first row
rowColl[0].Delete();
gXmlDoc.DataSet.AcceptChanges();

}

//Saves the current xml document
private void button2_Click(object sender, System.EventArgs e) {

System.Data.DataRowCollection rowColl =
gXmlDoc.DataSet.Tables["legendentry"].Rows;
for(int i=0; i<rowColl.Count; i++){
System.Diagnostics.Debug.WriteLine(rowColl["title"]);
}

SaveFileDialog dlg = new SaveFileDialog();
dlg.Title = "Save as" ;
dlg.InitialDirectory = System.IO.Directory.GetCurrentDirectory();
//@"c:\" ;
dlg.RestoreDirectory=false;
dlg.CheckPathExists=true;
dlg.ValidateNames=true;
dlg.Filter = "xml files (*.xml)|*.xml|All files (*.*)|*.*" ;
if(dlg.ShowDialog() == DialogResult.OK) {
this.gXmlDoc.Save(dlg.FileName);
}
}
}
}





Use the "Save as..." button to review the xml document after inserting rows.
 
G

Guest

I would say just swap the row contents...this one works...

//Using Rows.InsertAt:
private void button3_Click(object sender, System.EventArgs e)
{
System.Data.DataRowCollection rowColl =
gXmlDoc.DataSet.Tables["legendentry"].Rows;

object[] temp=rowColl[0].ItemArray;
rowColl[0].ItemArray=rowColl[1].ItemArray;
rowColl[1].ItemArray=temp;
gXmlDoc.DataSet.AcceptChanges();

}

i guess while serializing the dataset the framework does it by its own internal index.
--
Bharat Biyani ([email protected])
http://www.orcim.com



Troy McLure said:
I have a C# Windows form with a datagrid. The datagrid displays a
dataset. The dataset is created by reading an xml file. The dataset is
read into an XmlDataDocument. The datagrid and the xml data will not
sync when inserting new rows:

When I insert a new row to the dataset by using
System.Data.DataRowCollection.InsertAt, everything looks fine in the
datagrid. The problem is the xml in the XmlDataDocument. The data is
always inserted at the end of the document and one level too high in the
tree.

If I insert a new row by using XmlElement.InsertAfter, the xml in the
XmlDataDocument looks ok. But the new row always appears at the bottom
of the datagrid!

Any tips would be greatly appreciated!



proj.xml:

<?xml version="1.0" encoding="utf-8"?>
<webmapproject xmlns="http://tempuri.org/webmapproject.xsd">
<legendentries>
<legendentry>
<title>First title</title>
</legendentry>
<legendentry>
<title>Second title</title>
</legendentry>
<legendentry>
<title>Third title</title>
</legendentry>
<legendentry>
<title>Fourth title</title>
</legendentry>
</legendentries>
</webmapproject>



Form1.cs:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Xml;

namespace DataGridInsertion
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Xml.XmlDataDocument gXmlDoc;

private System.Windows.Forms.DataGrid dataGrid1;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button button3;

/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

string xmlFile = Application.StartupPath + "\\..\\..\\proj.xml";
try {
DataSet ds = new DataSet();
ds.ReadXml(xmlFile);
ds.EnforceConstraints=false;

gXmlDoc = new System.Xml.XmlDataDocument(ds);
dataGrid1.DataSource = ds;
this.dataGrid1.DataMember = "legendentry";

}
catch (Exception ex) {
MessageBox.Show(ex.ToString());
}
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.dataGrid1 = new System.Windows.Forms.DataGrid();
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.button3 = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.dataGrid1)).BeginInit();
this.SuspendLayout();
//
// dataGrid1
//
this.dataGrid1.DataMember = "";
this.dataGrid1.HeaderForeColor = System.Drawing.SystemColors.ControlText;
this.dataGrid1.Location = new System.Drawing.Point(8, 48);
this.dataGrid1.Name = "dataGrid1";
this.dataGrid1.Size = new System.Drawing.Size(472, 352);
this.dataGrid1.TabIndex = 0;
//
// button1
//
this.button1.Location = new System.Drawing.Point(192, 16);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(216, 24);
this.button1.TabIndex = 1;
this.button1.Text = "Move 0->2 using XmlElement.InsertAfter";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button2
//
this.button2.Location = new System.Drawing.Point(416, 16);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(64, 24);
this.button2.TabIndex = 2;
this.button2.Text = "Save as...";
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// button3
//
this.button3.Location = new System.Drawing.Point(8, 16);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(176, 24);
this.button3.TabIndex = 3;
this.button3.Text = "Move 0->2 using Rows.insertAt";
this.button3.Click += new System.EventHandler(this.button3_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(496, 406);
this.Controls.Add(this.button3);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Controls.Add(this.dataGrid1);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.dataGrid1)).EndInit();
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

//Using XmlElement.InsertAfter
private void button1_Click(object sender, System.EventArgs e) {
int insertIndex = 1;

System.Data.DataRowCollection rowColl =
gXmlDoc.DataSet.Tables["legendentry"].Rows;

XmlElement firstXmlElement = gXmlDoc.GetElementFromRow(rowColl[0]);
XmlElement parentXmlElement = (XmlElement)firstXmlElement.ParentNode;

//Insert a copy of the first row
XmlElement targetXmlElement =
gXmlDoc.GetElementFromRow(rowColl[insertIndex]);
XmlElement clonedXmlElement =
(XmlElement)firstXmlElement.CloneNode(true);
parentXmlElement.InsertAfter(clonedXmlElement, targetXmlElement);
gXmlDoc.DataSet.AcceptChanges();

//Remove the first row
firstXmlElement = gXmlDoc.GetElementFromRow(rowColl[0]);
parentXmlElement.RemoveChild(firstXmlElement);
gXmlDoc.DataSet.AcceptChanges();
}

//Using Rows.InsertAt:
private void button3_Click(object sender, System.EventArgs e) {
System.Data.DataRowCollection rowColl =
gXmlDoc.DataSet.Tables["legendentry"].Rows;

//Copy data from first row into a new one.
DataRow newRow = gXmlDoc.DataSet.Tables["legendentry"].NewRow();
newRow["title"] = rowColl[0]["title"];
rowColl.InsertAt(newRow,2);
gXmlDoc.DataSet.AcceptChanges();

//Delete first row
rowColl[0].Delete();
gXmlDoc.DataSet.AcceptChanges();

}

//Saves the current xml document
private void button2_Click(object sender, System.EventArgs e) {

System.Data.DataRowCollection rowColl =
gXmlDoc.DataSet.Tables["legendentry"].Rows;
for(int i=0; i<rowColl.Count; i++){
System.Diagnostics.Debug.WriteLine(rowColl["title"]);
}

SaveFileDialog dlg = new SaveFileDialog();
dlg.Title = "Save as" ;
dlg.InitialDirectory = System.IO.Directory.GetCurrentDirectory();
//@"c:\" ;
dlg.RestoreDirectory=false;
dlg.CheckPathExists=true;
dlg.ValidateNames=true;
dlg.Filter = "xml files (*.xml)|*.xml|All files (*.*)|*.*" ;
if(dlg.ShowDialog() == DialogResult.OK) {
this.gXmlDoc.Save(dlg.FileName);
}
}
}
}





Use the "Save as..." button to review the xml document after inserting rows.
 
T

Troy McLure

Thanks for the suggestion!

But what if I need to insert a new row? Since the InsertAt method
doesn't work, I would have to append a new row and start shifting the
other rows. Not very elegant.

Is the conclusion here that there is in fact a bug in the framework? Am
I really the only one with this problem?

Should I report it as a bug to Microsoft? How/where does one do that?
 
T

Troy McLure

Found this: http://tinyurl.com/42lvm

"In our bug database I see that it will be resolved in the next patch of
Visual Studio."

Great. Spent an entire day fighting this bug. :(


Troy said:
Thanks for the suggestion!

But what if I need to insert a new row? Since the InsertAt method
doesn't work, I would have to append a new row and start shifting the
other rows. Not very elegant.

Is the conclusion here that there is in fact a bug in the framework? Am
I really the only one with this problem?

Should I report it as a bug to Microsoft? How/where does one do that?


Bharat said:
I would say just swap the row contents...this one works...

//Using Rows.InsertAt:
private void button3_Click(object sender, System.EventArgs e) {
System.Data.DataRowCollection rowColl =
gXmlDoc.DataSet.Tables["legendentry"].Rows;

object[] temp=rowColl[0].ItemArray;
rowColl[0].ItemArray=rowColl[1].ItemArray;
rowColl[1].ItemArray=temp;
gXmlDoc.DataSet.AcceptChanges();

}

i guess while serializing the dataset the framework does it by its own
internal index.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top