LINQ to XML and DataGridView - c#

Hi I’m trying to use a DataGridView for the first time and with LINQ.
Here’s what I’m trying to do:
I want to use it (although it doesn’t have to the DataGridView ) to read and display the contents of an XML file (this bit is working code below) but I want to have an add row button on the form or in the DataGridView that takes the contents of three textboxes and and populates the contents of three columns of the new row. The new row is to be appended to the existing data.
Next I would like to add a Delete button to delete the currently selected row.
And lastly I want a save button that exports the contents of the DataGridView back to an XML file overwriting/updating the existing XML file.
So I stuck at adding the additional data! but as I don't currently have a clue as to the delete or save either I thought I would ask all in one go!!
So this is the code I have to read the xml file:
XDocument xmlDoc = XDocument.Load(#"queues.xml");
var q = from c in xmlDoc.Root.Descendants("Queue")
select new
{
QueueNumber = c.Element("Number").Value,
QueueName = c.Element("Name").Value,
QueuePCC = c.Element("QueueTag").Value
};
dataGridView1.DataSource = q.ToList();
XML document:
<?xml version="1.0" encoding="utf-8" ?>
<Queues>
<Queue>
<Number>
001
</Number>
<Name>
mytest
</Name>
<QueueTag>
xyz
</QueueTag>
</Queue>
<Queue>
<Number>
002
</Number>
<Name>
Adi2
</Name>
<QueueTag>
ABCD
</QueueTag>
</Queue>
</Queues>
ok I have now changed my code to this:
XDocument xmlDoc = XDocument.Load(#"queues.xml");
var q = from c in xmlDoc.Root.Descendants("Queue")
select new Queue
{
Number = c.Element("Number").Value,
Name = c.Element("Name").Value,
QueueTag= c.Element("QueueTag").Value
};
var queryAsList = new BindingList<Queue>(q.ToList());
bindingSource1.DataSource = queryAsList;
dataGridView1.DataSource = bindingSource1;
This allows me to add and delete rows and data from the dataGridView :)
But I can still find no way to writing the data back to XML either from the dataGridView or from the bindingSource1 :(
Any help please?
the bindingSource1.count changes each time I make a change to the data so I think I'm close!

Perhaps you may try working with the xmlDoc saved in the session (thus preserved with the postbacks)... Add the three elements (from the textboxes) to the XmlDoc... And rebind the gridview to the xmlDoc at each postback.
At the end, you could do xmlDoc.save().
For deleting rows, you could use the GridView event, dataGridView1_RowDeleted, to edit the xmlDoc (to remove the node relative to the selected row).
Something like:
protected void ButtonLoadGridView_Click(object sender, EventArgs e)
{
XDocument xmlDoc = XDocument.Load(#"f:\queues.xml");
var q = from c in xmlDoc.Root.Descendants("Queue")
select new
{
QueueNumber = c.Element("Number").Value,
QueueName = c.Element("Name").Value,
QueuePCC = c.Element("QueueTag").Value
};
dataGridView1.DataSource = q.ToList();
Session.Add("xmlDoc",xmlDoc);
}
public void dataGridView1_RowDeleting(Object sender, GridViewDeleteEventArgs e)
{
// get some node information:
int rowIndex = e.RowIndex;
string someNodeInfo = dataGridView1.Rows[rowIndex].Cells[0].Text;
// then edit xml :
XmlDocument xmlDoc = (XmlDocument) Session["xmlDoc"];
xmlDoc.ChildNodes.Item(rowIndex).RemoveAll();
Session.Add("xmlDoc", xmlDoc);
}
protected void ButtonSave_Click(object sender, EventArgs e)
{
XmlDocument xmlDoc = (XmlDocument)Session["xmlDoc"];
xmlDoc.Save(#"f:\queues2.xml");
}

Related

ASP.NET GridView update Source but not commands

I have a gridview. Its datasource is taken from XML by adding some xmlElemens in a list and than set the list as its data source. Now I am implementing a search feature.
So I am filtering the list in this way:
protected void btnSearch_Click(object sender, EventArgs e)
{
XmlDocument doc = new XmlDocument();
doc.Load(prog); //Percorso file xml
List<string> nomi = new List<string>();
XmlElement root = doc.DocumentElement;
XmlNodeList elemLists = root.GetElementsByTagName("nome");
// this binds the gridview to the title text to display
for (int i = 0; i < elemLists.Count; i++)
{
if(elemLists[i].InnerXml.ToString().ToLower().StartsWith(txtSearchMaster.Text.ToLower()) ||
elemLists[i].InnerXml.ToString().ToLower() == txtSearchMaster.Text.ToLower() ||
elemLists[i].InnerXml.ToString().ToLower().EndsWith(txtSearchMaster.Text.ToLower()) ||
elemLists[i].InnerXml.ToString().ToLower().Contains(txtSearchMaster.Text.ToLower()))
nomi.Add(elemLists[i].InnerXml.ToString());
}
GridView1.DataSource = nomi.OrderBy(q => q).ToList();
GridView1.DataBind();
}
The data is shown correctly but the problem is that when I click the button next the column that is auto generated and get the cell content (that is an element of the list) it return the content of the cell at the same index but of the previous data.
How can I overcome to this?
The problem here is that your "filter" as it were is only applied on the search click. If you had hidden state where a search term was stored, and applied it on every postback, if the state exists, then clicking your grid button would work.
<asp:HiddenField ID="SearchString" runat="server" value="" />
and in your btnSearch_Click
SearchString.Value = txtSearchMaster.Text.ToLower().Trim();
and then add the filter logic in Page_Load
if (IsPostBack) {
// filter on hidden value if not empty.
if (!String.IsNullOrEmpty(SearchString.Value)) {
// filter here
}
}
Just fixed by adding
if (!IsPostBack)
{
...
}
in Page_Load and leaving the filter login into the search button click method.

how to filter a grid based on codtions and than bind the grid using xml

I have one text box and a button and a grid
textbox ID-->Client side---------------->txtFirstName
button Name-->Client side--------------->btnSearch
Grid id-->Client side------------------->gvContactUS
On click of button Search i am trying to search a record which i have entered in textbox whose name is is their in the xml file and will show that in the grid
my xml file is :Contact.xml
<CATALOG>
<CD>
<ID>1</ID>
<HeaderDetailID>1</HeaderDetailID>
<FirstName>Basant</FirstName>
<LastName>Gera</LastName>
<EmployeeID>0012</EmployeeID>
<Department>SD</Department>
<Postion>Programmer</Postion>
<Application>P and L - Joint Cost***BI_AP_KL_COST</Application>
<Filter>Africa_ww_READ</Filter>
<AreaorCountryorStation>India</AreaorCountryorStation>
<NetworkDomain>.Net</NetworkDomain>
<Action>
Modification
</Action>
<NameOfController>Nitin</NameOfController>
</CD>
</CATALOG>
I am trying to filter only 1 record which is their into the grid.
But i am getting the full grid.
Code as follows:
protected void btnSearch_Click(object sender, EventArgs e)
{
string FilepathContact;
string FirstName = txtFirstName.Text;
FilepathContact = Server.MapPath("~/Contact.xml");
DataSet dsdata = new DataSet();
dsdata.ReadXml(FilepathContact);
}
if (dsdata.Tables["CD"].Rows.Count != 0)
{
for (int i = 0; i < dsdata.Tables["CD"].Rows.Count; i++)
{
if (Convert.ToString(dsdata.Tables["CD"].Rows[i]["FirstName"]) == Convert.ToString(FirstName))
{
gvContactUS.DataSource = dsdata;
gvContactUS.DataBind();
}
}
}
}
Now I am getting all the records which is their in my grid.
How do i find the element and search if its their than bind the grid only with that record which is their in data set.
I am using .net Framework 2.0 so LINQ dont work her.

Select row from DataGridView and place it in a textbox

I have a windows form application which has a datagridview to display a menu full of meals.
I want to be able to allow the user to choose a seat number and then select a row and once the row is selected all the information in that row to be put in the available textbox below which will then be submitted in a new xml file titled order.xml.
So far I have the the saving to the xml part sorted, but I can't seem to get the datagridview task done.
Code to save the data in the order.xml file.
XDocument doc = XDocument.Load("order.xml");
XElement root = new XElement("MenuInfo");
root.Add(new XElement("Data1", dataGridView.DataSource));
root.Add(new XElement("Data2", _seat));
root.Add(new XElement("Data3", buttonTable1.Text));
root.Add(new XElement("Data4", lbPrice.Text));
doc.Element("Menu").Add(root);
doc.Save("order.xml");
MessageBox.Show("The order has been placed.");
You can react on the RowEnter-Event, which fires if the user enter a row. Do following then:
private void dataGridView1_RowEnter(object sender, System.Windows.Forms.DataGridViewCellEventArgs e)
{
var yourGrid = sender as DataGridView;
if (yourGrid != null)
{
var row = yourGrid.Rows[e.RowIndex].DataBoundItem as DataRowView;
if (row != null)
{
//Here you have access to the actual row.
//So simply get the string foreach column you need
string myStringForTextEdit = Convert.ToString(row["MealID"]) + Convert.ToString(row["Food"]) +
Convert.ToString(row["Price"]) + Convert.ToString(row["Time"]) +
Convert.ToString(row["Quantity"]);
myTextEdit.Text = myStringForTextEdit;
}
}
}
This simple example use the RowEnter-Event gets the current row and build a string based on all row Values.
I hope this helps.

How to show a display value for selected node in treeview in C#?

I am trying to create a treeview which pulls info from a sql database. I want the text to be the name field but when you double click the name i want it to display the id field. I have look and looked but cant find any info on this?
Code tried (Added from OP's comment):
foreach (DataRow dr in Db.Table("Employee").Rows)
{
treeView1.Nodes.Add(
new TreeNode(dr["Name"].ToString(),
new TreeNode[] {new TreeNode(dr["EEID"].ToString())}));
}
var node = treeView1.SelectedNode.Nodes[0].Text;
MessageBox.Show(string.Format("You selected: {0}", node));
When you create new nodes for a TreeView you can specify a text value and a key value, like so:
TreeView tv = new TreeView();
tv.Nodes.Add(key, text); //where key is your database id value, and text the display
Then you'd simply return the key of the clicked node. Is this what you want?
EDIT: This is what happens when you speak from memory... this is wrong. 'key' is not a hidden key value, like an ID, 'key' is the name of the tree node. Please hold while I give you a proper solution.
** EDIT2 (SOLVED) ** : You can also use the Name property. Like this:
tView.Nodes.Add("Id_0001", "Mr. Dexter");
then you could retrieve the values of that node with something like this:
private void tvView_AfterSelect(object sender, TreeViewEventArgs e)
{
TreeNode node = e.Node;
MessageBox.Show(node.Name + "\n" + node.Text);
}
which would yield the results: "Id_0001" and "Mr. Dexter".
foreach (DataRow dr in Db.Table("Employee").Rows)
{
TreeNode tn = new TreeNode();
tn.Tag = dr["eeid"];
tn.Text = dr["Name"].ToString();
treeView1.Nodes.Add(tn);
}
private void treeView1_DoubleClick(object sender, EventArgs e)
{
MessageBox.Show(treeView1.SelectedNode.Tag.ToString());
}
you can use Mouse Click event. when you click on a particular node (assume it's not WPF cause then it's Items) you can get its Text from SelectedNode property.
private void btnGetNodeValue_Click(object sender, EventArgs e)
{
string nodeVal= treeView1.SelectedNode.Text;
}
then you can pass this string value to database to retrieve your value,mix up with Select statement and WHERE clause so you can easily get it.

save new rows in dataset back out to xml

Can't quite figure out what else I need to do to make this work.
I am trying to add more rows to my dataset and datagridview then output either one to an xml
Ideally I want to save the values in dataset then bind datagridview and when closing the form output the dataset out to an xml file. But for some reason this doesn't work. It does update changes to current rows but doesn't add new rows.
public void LoadSongInfo(string filename)
{
TagLib.File tagFile = TagLib.File.Create(filename);
string artist = tagFile.Tag.FirstAlbumArtist;
string album = tagFile.Tag.Album;
string title = tagFile.Tag.Title;
DataRow newtrack = dsStore.Tables["Track"].NewRow();
newtrack["Id"] = "5";
newtrack["Artist"] = artist;
newtrack["Album"] = album;
newtrack["Filepath"] = filename;
newtrack["Title"] = title;
dsStore.Tables["Track"].Rows.Add(newtrack);
dsStore.Tables["Track"].AcceptChanges();
dataGridView1.DataMember = "Track";
dataGridView1.DataSource = dsStore;
}
private void mediaplayer_FormClosing(object sender, FormClosingEventArgs e)
{
string path = "..//..//..//temp.xml";
dataGridView1.EndEdit();
if (dsStore.GetChanges() != null)
{
dsStore.WriteXml(path);
}
}
I have noticed that
dsStore.GetChanges()
returns null unless cell has been edited. So I tried removing that if statement but still nothing.
EDIT: I've tried to write to an empty xml file to see if it writes at least something, and no errors it goes through like everything is ok, then when i open up test2.xml its blank nothing was written. :(
private void mediaplayer_FormClosing(object sender, FormClosingEventArgs e)
{
string path2 = "..//..//..//test2.xml";
dsStore.WriteXml(path2);
}
You have the line:
dsStore.Tables["Track"].AcceptChanges();
This will update the RowState to 'DataRowState.Unchanged' for every row in that table. This is why
dsStore.GetChanges()
is not returning any changes.
Try removing the AcceptChanges() call.
Try removing the
dataGridView1.EndEdit();
this is used if a cell is being edited so the fact that it's only working when you edit a cell could be caused because of that line.
Ok I got this to work..
First mistake what that I was trying to WriteXml in the LoadSong function which can't be done because that function is being called from a ForEach Loop.
I then went to my FormClosing and just did it this way:
private void mediaplayer_FormClosing(object sender, FormClosingEventArgs e)
{
dsStore.WriteXml(path);
}
And last not sure if it's needed but I set my dataset on top like this:
public DataSet dsStore = new DataSet();
added the "public" in case it wasn't keeping the values..Thanks everyone for you help.

Categories