1

I am using WPF datagrid bound to a database via the Visual Studio IDE drag and drop, and found a way to have my datagrid update and add to the database in real time using the RowEditEnding event thusly:

private void Update_WatchList(object sender,
    DataGridRowEditEndingEventArgs e)
{
    UpdateWatchList();
}

private void UpdateWatchList()
{
    dsDocControlTableAdapters.DocumentWatchListTableAdapter ta =
        new dsDocControlTableAdapters.DocumentWatchListTableAdapter();
    try
    {
        DataRowView dr =
            (DataRowView)documentWatchListDataGrid.SelectedItem;
        dsDocControl.DocumentWatchListRow dr1 =
            (dsDocControl.DocumentWatchListRow)dr.Row;
        dr1.EndEdit();
        if (dr1.RowState == DataRowState.Detached)
            dsDocControl.DocumentWatchList.AddDocumentWatchListRow(dr1);
        ta.Update(dr1);
    }
    catch (Exception ex)
    {
        MessageBox.Show("Error UpdateWatchList:\n" + ex.Message);
    }
}

This was the result of much trial and error (during which time I missed, rescheduled and missed again a dental appointment) but somehow stumbled across the need to call EndEdit() on the row for the RowState to be updated to either Modified or Detached. Is this the expected sequence of operations for what seems to be a very normal use case, or is there a better way to do this?

I had started to go the route of adding a CollectionChanged event handler for the added rows, but could not get it to work probably because I don't properly use the ObservableCollection<T>:

private void documentWatchListDataGrid_Loaded(object sender,
    RoutedEventArgs e)
{
    var dg = (DataGrid)sender;
    if(dg==null || dg.ItemsSource == null) return;
    var sourceCollection = dg.ItemsSource as ObservableCollection<DataRow>;
    if (sourceCollection == null) return;
    //sourceCollection.CollectionChanged +=
    new NotifyCollectionChangedEventHandler(Update_WatchList); // Never gets called.
}

The line that adds the handler is commented out because I used the handler as the RowEditEnding (in the first code block) but regardless it never to to that point because sourceCollection was always null.

My question is, what is the best practices way to do this seemingly simple thing: update in real time as each row is changed or added in a WPF datagrid control?

Toni
  • 1,555
  • 4
  • 15
  • 23
Paul Gibson
  • 622
  • 1
  • 9
  • 23

1 Answers1

3

Is this the expected sequence of operations for what seems to be a very normal use case, or is there a better way to do this?

No, that is not the normal method of working with DataGrids in WPF. That looks like it may be normal for WinForms, but not WPF. :)

The typical method of binding a DataGrid.ItemsSouce is to build a class that inherits INotifyPropertyChanged to represent each row of data, and bind DataGrid.ItemsSource to an ObservableCollection<T> of that class

For example, you may have something like

public class WatchListModel : INotifyPropertyChanged
{
    // Whatever properties here
    public string Id { get; set; }
    public string Name { get; set; }
}

This class should implement INotifyPropertyChanged, and properties should raise change notifications, however I've left it out for simplicity. If you need an example, check out here.

Then you'd have an ObservableCollection<WatchListModel> that you would be binding your DataGrid.ItemsSource too

public ObservableCollection<WatchListModel> WatchListCollection { get; set; }

and

<DataGrid ItemsSource="{Binding WatchListCollection}" ... />

And if you wanted real-time updates, you'd add a collection changed event handler for WatchListCollection to handle add/remove, and add a property changed handler to each item to handle when its modified

public MyViewModel()
{
    WatchListCollection = new ObservableCollection<WatchListModel>();

    // Hook up initial changed handler. Could also be done in setter
    WatchListCollection.CollectionChanged += WatchListCollection_CollectionChanged;
}

void WatchListCollection_CollectionChanged(object sender, CollectionChangedEventArgs e)
{
    // if new itmes get added, attach change handlers to them
    if (e.NewItems != null)
        foreach(WatchListModel item in e.NewItems)
            item.PropertyChanged += WatchListModel_PropertyChanged;

    // if items got removed, detach change handlers
    if (e.OldItems != null)
        foreach(WatchListModel item in e.OldItems)
            item.PropertyChanged -= WatchListModel_PropertyChanged;

    // Process Add/Remove here
}

void WatchListModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    // Process Update here
}

That would be the proper WPF way to do it :)

Community
  • 1
  • 1
Rachel
  • 130,264
  • 66
  • 304
  • 490
  • Interesting, I will set up a new WPF project to play with what you have outlined. This is still greek to me but I'm starting to make some connections. However, when you say this is typical, why isn't this how the IDE creates and implements the objects with the "drag and drop" dataset creation? IOW, it seems that in order to implement this method (the best practices way to do things) you cam not rely on the ide to do anything apart from compilation and debugging: which appeals to me (I cut my teeth on Xt/Xm Motif on Unix systems, my ide was vi) but steep learning curve. – Paul Gibson Oct 29 '14 at 16:44
  • One big question for me is how the TableAdapter functions play out in the model you outline above. The other is the IDE maps the datagrid to a ViewSource resource that handles the presentation. But this all changes (it seems) with the use of ObservableCollection binding. Since I don't really understand how it all works in the model I've got, I'm not really sure how to even phrase my questions. So I'll keep reading and experimenting. Thanks for the help :) – Paul Gibson Oct 29 '14 at 16:47
  • 1
    @PaulGibson I would highly recommend learning to use the MVVM pattern too from the start. It's well suited to WPF and makes life a whole lot easier. Also if you're interested, I like to blog about WPF for beginners, and you can find the summary of newbie links in this answer if you want : [Transitioning from Windows Forms to WPF](http://stackoverflow.com/a/15684569/302677) – Rachel Oct 29 '14 at 16:47