Paul Gibson
Paul Gibson

Reputation: 634

WPF DataGrid RowEditEnding Event to call Update

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?

Upvotes: 1

Views: 4531

Answers (1)

Rachel
Rachel

Reputation: 132548

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 :)

Upvotes: 3

Related Questions