Reputation: 634
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
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