views:

6246

answers:

4

I have a project with an XmlDataProvider bound to a WPF DataGrid control. I have the bindings on the DataGrid set up as follows:

<dg:DataGrid ItemsSource="{Binding Source={StaticResource XmlData}, XPath=Root/People/Person}"
             AutoGenerateColumns="False">
    <dg:DataGrid.Columns>
        <dg:DataGridTextColumn Header="ID" Binding="{Binding XPath=ID}"/>
        <dg:DataGridTextColumn Header="Name" Binding="{Binding XPath=Name}"/>
    </dg:DataGrid.Columns>
</dg:DataGrid>

Users can edit entries using the DataGrid without any problems. What I cannot manage to accomplish is allowing the user to add a new row (i.e. a new Person) using the DataGrid. How can I allow this?

A: 

Have you tried setting CanUserAddRows="True" on the DataGrid?

Yes, I have tried CanUserAddRows="True".
bluepolystyreneman
I ran into this same problem today. I have explicitly set CanUserAddRows = true, but it turns to false immidiately as I found from the Immediate Window. The reason is that the binding class doesn't have a default constructor. Once I added the default constructor, I got the new row at the end.
miliu
A: 

Is the problem that the user can't add rows or is it that when the user does add a row, it's not saved to the backing XML store? I can easily add a datagrid with CanUserAddRows="True" to a WPF application, bind the grid to an in-memory list and then have the user add rows that are reflected in that in-memory list. That makes me think that your problem is saving to the backing store.

When I bind to an XML on the file system, I can no longer add records to the data grid. I think you will need a minor workaround in that you read the file into an in-memory collection, bind to that and then update the file accordingly as users add rows.

Brett Bim
A: 

Make sure that you set CanUserAddRows="True" and the default constractor of a bound class is available.

Boris Lipschitz
+1  A: 

To add a row to a WPF DataGrid that is bound to an XmlDataSource, you need to directly modify the backing data store. You can use the DataGrid to collect the new row information from the user and then in the RowEditEnding event, you can add the row's information to your backing store and prevent the DataGrid from actually trying to commit the edit using its internal logic. Since the DataGrid is bound to the XmlDataSource, it will display the changes you made to the backing store.

Here is the general idea:

private void MyDataGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
{
  if (e.EditAction == DataGridEditAction.Cancel)
  {
    e.Cancel = false;
    return;
  }

  if (e.EditAction == DataGridEditAction.Commit)
  {
    DataGridRow dgr = e.Row;
    XmlElement xe = myXmlDataProvider.Document.CreateElement("NewRowElement");
    foreach(DataGridCell cell in dgr.Cells)
    {
      xe.SetAttribute(cell.Name, cell.Value);
    }
    dataProvider.Document.DocumentElement.AppendChild(xe);
    e.Cancel = true;
  }
}
Timothy Lee Russell