简体   繁体   English

WPF 使用 Entity Framework Core 模型时数据网格未更新

[英]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.我有一个 WPF window 来显示培训 class 的详细信息,以及数据网格中的参与者列表。

I am using Entity Framework Core and my training class model looks like this我正在使用 Entity Framework Core,我的训练 class model 看起来像这样

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在我的TrainingClassDetailsViewModel中,我有一个按钮可以打开对话框 window,用户可以在其中输入与会者详细信息并单击“保存”按钮

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.这会添加新的参与者,因此 EF Core 可以在调用SaveChanges时更新数据库,但这不会更新数据网格。

I'm aware I need to use ObservableCollection which uses INotifyPropertyChanged .我知道我需要使用ObservableCollection ,它使用INotifyPropertyChanged If I implement the following and use Attendees.Add(attendee);如果我实施以下并使用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);我能得到的唯一工作方法是同时执行_trainingClass.TrainingAttendees.Add(attendee); and Attendees.Add(attendee);Attendees.Add(attendee); . . But I find this odd by managing 2 lists.但我发现管理 2 个列表很奇怪。 And I need my own ApplyPropertyChanged to be called instead.我需要调用我自己的ApplyPropertyChanged

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> ).您可以使用ObservableCollection<T>作为集合导航属性的后备存储(代替当前的HashSet<T> )。 Or even better, the EF Core provided ObservableHashSet<T> class. eg或者甚至更好,EF Core 提供了ObservableHashSet<T> class。例如

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.有关详细信息,请参阅官方 EF Core 文档中的通知实体部分和整个更改跟踪主题。

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.此外,如果您使用的是 EF Core 5.0 或更高版本,则可以利用 EF Core 更改跟踪代理,这些代理基本上为您实现了所有INotifyPropertyChangingINotifyPropertyChanged功能。 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.但是您需要将所有属性设为虚拟,并且还可以访问DbContext并使用CreateProxy扩展方法而不是new来创建新的实体实例。

This is a good example why you should not bind directly to auto-generated (EF) model classes.这是一个很好的例子,为什么你不应该直接绑定到自动生成的 (EF) model 类。

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> :在您的AddAttendee方法中,您将像您当前所做的那样将实体添加到上下文中,但还将视图模型/包装器添加到数据绑定的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 .您会在此处找到“包装”model 的视图 model class 的示例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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