views:

243

answers:

1

Learning LINQ has been a lot of fun so far, but despite reading a couple books and a bunch of online resources on the topic, I still feel like a total n00b. Recently, I just learned that if my query returns an Anonymous type, the DataGridView I'm populating will be ReadOnly (because, apparently Anonymous types are ReadOnly.)

Right now, I'm trying to figure out the easiest way to:

  1. Get a subset of data from an XML file into a DataGridView,
  2. Allow the user to edit said data,
  3. Stick the changed data back into the XML file.

So far I have Steps 1 and 2 figured out:

public class Container
{
    public string Id { get; set; }
    public string Barcode { get; set; }
    public float Quantity { get; set; }
}

// For use with the Distinct() operator
public class ContainerComparer : IEqualityComparer<Container>
{
    public bool Equals(Container x, Container y)
    {
        return x.Id == y.Id;
    }

    public int GetHashCode(Container obj)
    {
        return obj.Id.GetHashCode();
    }
}

var barcodes = (from src in xmldoc.Descendants("Container")
        where src.Descendants().Count() > 0
        select
        new Container
        {
           Id = (string)src.Element("Id"),
           Barcode = (string)src.Element("Barcode"),
           Quantity = float.Parse((string)src.Element("Quantity").Attribute("value"))
        }).Distinct(new ContainerComparer());

dataGridView1.DataSource = barcodes.ToList();

This works great at getting the data I want from the XML into the DataGridView so that the user has a way to manipulate the values.

Upon doing a Step-thru trace of my code, I'm finding that the changes to the values made in DataGridView are not bound to the XDocument object and as such, do not propagate back.

How do we take care of Step 3? (getting the data back to the XML) Is it possible to Bind the XML directly to the DataGridView? Or do I have to write another LINQ statement to get the data from the DGV back to the XDocument?

Suggstions?

+1  A: 

So I think the problem that you have is that there is no relationship between the objects you are binding to and the XML source document.

What you are doing is creating a heap of objects, pushing in some strings and a float, and then binding the grid view to that list of objects. All the objects know is that some data was given in the constructor, it has no knowledge of where that data come from. When you call "select new something()" you are creating a new object, that new object doesn't know or care that it was created using LINQ to XML...

The easiest way I can think of to resolve it would be to change the setter of your container properties so that they load the XML, change the element they are supposed to represent, and then save the xml again. Perhaps giving the Container a reference to the element or document would make this easier.

The other way would be to hook into the grid view events so that when rows are edited you can capture the changes and write them to the XML file.

Glenn Condron
Hmmm... I think I see what you're getting at. This is sort of the conversation I was looking to have with someone. Since it's not clear to me what's going on behind the scenes, I'm not sure what I should be expecting of all this "LINQ Magic". I was under the impression that LINQ was returning references to positions in the XDocument and that wiring it up to the DGV would allow changes to directly propagate back. But that seems kinda silly now. (or perhaps too easy.) Programming is never easy. (Although it is still a lot of fun.) I guess I need to think about this some more...
Pretzel
Ok, I've thought about it more and it's abundantly clear to me now that as soon as I CAST each XML element to another object, I'm working with a copy. (There is no reference back to the XML/XDocument.) I'll have to think more about making a way to have direct references to/from XML documents (and if it is even worth programming something like this.) Thanks again, Glenn! :-)
Pretzel