Search code examples
c#wpfxpathcode-behind

WPF Code Behind: DataGridTextColumn shows Column headers but not data from xmlprovider with xpath


I'm trying to show data from XMLProvider with XPath. Because of the the dynamic nature of the xml file I need to load the data via code behind.

I'm looking for a datagrid looking like this:

Sensor    BIS  MAN  BIS  MAN
-----------------------------
Sensor1   45   43   44   46
Sensor2   45   43   43   45

FYI: above the grid I'll be showing a fake super header to group BIS & MAN values (in case you don't understand why BIS & MAN keywords are repeating)

XAML code for the datagrid:

<DataGrid Name="MDataGrid" AutoGenerateColumns="False"></DataGrid>

This is the XML file sample data:

<?xml version="1.0" encoding="utf-8" ?>
<ShipData>
  <Draught>
    <Measures>
      <Mdata>M1</Mdata>
      <Mdata>M2</Mdata>
    </Measures>
    <Sensor Name="Sensor1">
      <Measurement>
        <Bis>45</Bis>
        <Man>43</Man>
      </Measurement>
      <Measurement>
        <Bis>44</Bis>
        <Man>46</Man>
      </Measurement>
    </Sensor>
    <Sensor Name="Sensor2">
      <Measurement>
        <Bis>45</Bis>
        <Man>43</Man>
      </Measurement>
      <Measurement>
        <Bis>43</Bis>
        <Man>45</Man>
      </Measurement>
    </Sensor>
  </Draught>
</ShipData>

And here is the code behind c# code I'm using:

// loading xml for grid
XmlDocument doc = new XmlDocument();
doc.Load(_file_location_); // (it does find the xml)

// setting the xml provider
XmlDataProvider _xmlDataProvider = new XmlDataProvider();
_xmlDataProvider.Document = doc;
_xmlDataProvider.XPath = @"/ShipData/Draught/Sensor";

// Setting the datacontext for 
MDataGrid.DataContext = _xmlDataProvider; 

// Creating the column Sensor (as an example) and create a new binding for xpath
var dataGridTextColumn = new DataGridTextColumn();

Binding bindingSensor = new Binding();
bindingSensor.Source = _xmlDataProvider;
bindingSensor.XPath = "@Name";
dataGridTextColumn.Binding = bindingSensor;

dataGridTextColumn.Header = "Sensor";

// other repeating columns (bis+man ...) omitted for this example

// adding the column to the datagrid
MDataGrid.Columns.Add(dataGridTextColumn);

The header for the sensor column is showing, but there's no data listed in the grid. Where am I wrong?


Solution

  • Apparently you need an extra Binding as someone else pointed me out. I don't know why exactly, but it does the job perfectly.

    // loading xml for grid
    XmlDocument doc = new XmlDocument();
    doc.Load(_file_location_); // (it does find the xml)
    
    // setting the xml provider
    XmlDataProvider _xmlDataProvider = new XmlDataProvider();
    _xmlDataProvider.Document = doc;
    _xmlDataProvider.XPath = @"/ShipData/Draught/Sensor";
    
    // Setting the datacontext (updated code)
    Binding binding = new Binding();
    binding.Source = _xmlDataProvider;
    MDataGrid.SetBinding(DataGrid.ItemsSourceProperty, binding);
    
    // Creating the column Sensor (as an example) and create a new binding for xpath
    var dataGridTextColumn = new DataGridTextColumn();
    
    Binding bindingSensor = new Binding();
    bindingSensor.XPath = "@Name";
    dataGridTextColumn.Binding = bindingSensor;
    
    dataGridTextColumn.Header = "Sensor";
    
    // other repeating columns (bis+man ...) omitted for this example
    
    // adding the column to the datagrid
    MDataGrid.Columns.Add(dataGridTextColumn);
    

    It does also work for the added columns I wanted (using dynamically adjusted XPath code)

    Credit goes to: Magnus (MM8)