简体   繁体   中英

WPF datagrid not updating when using Entity Framework Core Models

I have a WPF window to display details of a training class, and a list of attendees in a datagrid.

I am using Entity Framework Core and my training class model looks like this

public partial class TrainingClass
{
    public TrainingClass()
    {
        TrainingAttendees = new HashSet<TrainingAttendee>();
    }

    public int ClassId { get; set; } // PK
    public DateTime DateFrom { get; set; }
    public DateTime DateTo { get; set; }
    public string CourseName { get; set; }

    public virtual ICollection<TrainingAttendee> TrainingAttendees { get; set; }
}

In my TrainingClassDetailsViewModel I have a button that opens a dialog window where the user enters in the attendee details and clicks a Save button

public void AddAttendee(object parameter)
{
    TrainingAttendee attendee = new TrainingAttendee()

    TrainingAttendeeViewModel vm = new TrainingAttendeeViewModel(attendee);
    _windowService.ShowDialog<TrainingAttendeeEditor>(vm);

    if (vm.SaveClicked)
    {
        _trainingClass.TrainingAttendees.Add(attendee);
    }
}

This adds the new attendee so EF Core can update the database when SaveChanges is called, but this does not update the datagrid.

I'm aware I need to use ObservableCollection which uses INotifyPropertyChanged . If I implement the following and use Attendees.Add(attendee); instead, this will update the datagrid, but will not update the database.

private ObservableCollection<TrainingAttendee> _attendees;
public ObservableCollection<TrainingAttendee> Attendees
{
    get => _attendees;
    set
    {
        if (_attendees != value)
        {
            _attendees = value;
            ApplyPropertyChange();
        }
    }
}

...

_attendees = new ObservableCollection<TrainingAttendee>(_trainingClass.TrainingAttendees);

The only working method I can get is to do both _trainingClass.TrainingAttendees.Add(attendee); and Attendees.Add(attendee); . But I find this odd by managing 2 lists. And I need my own ApplyPropertyChanged to be called instead.

How would I best implement this?

You can use ObservableCollection<T> as a backing store for your collection navigation properties (in place of the current HashSet<T> ). Or even better, the EF Core provided ObservableHashSet<T> class. eg

using Microsoft.EntityFrameworkCore.ChangeTracking; // <-- required

public partial class TrainingClass
{
    public TrainingClass()
    {
        TrainingAttendees = new ObservableHashSet<TrainingAttendee>(); // <--
    }

    //...

    public virtual ICollection<TrainingAttendee> TrainingAttendees { get; set; }
}

For more info, see Notification entities section and the whole Change Tracking topic in the official EF Core documentation.

Also, if you are using EF Core 5.0 or later, you can utilize EF Core Change-tracking proxies which basically implement all INotifyPropertyChanging and INotifyPropertyChanged functionality for you. But you need to make all your properties virtual and also have access to DbContext and use CreateProxy extension method instead of new for creating new entity instances.

This is a good example why you should not bind directly to auto-generated (EF) model classes.

You should bind to view models or wrapper classes and convert/map between your entity objects and these.

In your AddAttendee method you wold then add the entity to the context like you are currently doing but also add a view model/wrapper to a data-bound ObservableCollection<T> :

if (vm.SaveClicked)
{
     //1. add to EF context
    _trainingClass.TrainingAttendees.Add(attendee);
     //2. Add to source data-bound collection
    vm.SourceCollection.Add(new Wrapper(attendee));
}

You'll find an example of a view model class that "wraps" a model here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM