views:

1100

answers:

2

I have looked for and tried various solutions but so far none of them solve my problem. I am using the built-in DataGrid from WPF in Visual Studio 2010/.NET4 to display data from an XML document stored as an XDocument.

My code all runs fine, and I have verified that the XDocument is present and correct. The DataGrid does not display any data, however.

The XML looks like this (simplified for clarity):

<data>
  <track>
    <id>211</id>
    <name>Track Name</name>
    <duration>156</duration>
    <artist_id>13</artist_id>
    <artist_name>Artist Name</artist_name>
    <album_id>29</album_id>
    <album_name>Album Name</album_name>
  </track>
...
</data>

My XAML looks like this:

<DataGrid x:Name="LibraryView" Grid.Row="1"
              DataContext="{Binding Path=TrackList}" ItemsSource="{Binding XPath=/data/track}">
    <DataGridTextColumn Header="Title" Binding="{Binding XPath=name}"/>
    <DataGridTextColumn Header="Artist" Binding="{Binding XPath=artist_name}"/>
    <DataGridTextColumn Header="Album" Binding="{Binding XPath=album_name}"/>
    <DataGridTextColumn Header="Length" Binding="{Binding XPath=duration}"/>
</DataGrid>

The C# that backs it up just assigns a new XDocument (downloaded from a web service) to the TrackList property (which implements INotifyPropertyChanged). No further processing is done on it.

I have previously tried using XLinq, to bind to a query result, which didn't work either (same problem), so I thought I'd try the XPath approach to avoid writing a potentially buggy Linq statement, and try to find the problem.

I am running out of ideas for how to get the DataGrid to display correctly. My understanding of how this is supposed to work is clearly lacking, so I would greatly appreciate any help offered.

Edit: It is worth noting that I have some flexibility with the input data format, as I am downloading raw XML myself. I will try some of the suggestions and see what I can get to work.

+1  A: 

Binding XPath is only relevant if you are binding to something that is an XmlNode (e.g. you are using XmlDataProvider). See here.

XPath does not work with XDocument classes. The only way to bind to properties of an XDocument is the normal Path syntax, which is not XML aware.

Your best bet is either to use the XmlDataSource, or convert your Xml document via XDocument into a POCO. That is pretty simple using LINQ:

XDocument doc = XDocument.Load(xmlFile);

            var tracks = from track in doc.Descendants("data") 
                    select new Track()
                               {
                                   Name= track.Element("name").Value,    
                                   Duration= track.Element("duration").Value,    
                                   etc ... 
                               };
LibraryView.ItemsSource = tracks;
Schneider
+2  A: 

I used XLinq and worked fine, using a XElement instead a XDocument :

XElement TrackList = XElement.Load("List.xml");
LibraryView.DataContext = TrackList;

Xaml:

<DataGrid x:Name="LibraryView" ItemsSource="{Binding Path=Elements[track]}">
    <DataGrid.Columns>
         <DataGridTextColumn Header="Artist" Binding="{Binding Path=Element[artist_name].Value}"/>
         <DataGridTextColumn Header="Album" Binding="{Binding Path=Element[album_name].Value}"/>
         <DataGridTextColumn Header="Length" Binding="{Binding Path=Element[duration].Value}"/>
    </DataGrid.Columns>
</DataGrid>
Natxo
This raises an InvalidOperationException with the message, "Items collection must be empty before using ItemsSource. This happens when performing the assignment to the DataContext, or in the event handler for PropertyChanged, so prevents either implementation.Edit: No it doesn't, I forgot to add <DataGrid.Columns> around my column definitions.
IanGilham
The Exception was my mistake. This works fine.
IanGilham
Oh man, debugging xaml can be obnoxious.
Natxo