Search code examples
wpfentity-framework-coreobservablemvvm-toolkit

EF Core Scaffolded data and Property Changed


I have a WPF application (MVVM Toolkit) with a data model which was scaffolded using EFcore tools from a database. The resulting model for one specific class looks like this:

public partial class BomLine
{
    public int Id { get; set; }
    public int ProjectId { get; set; }
    public string? Manufacturer { get; set; }
    public string? ManufacturerPartNumber { get; set; }

    public string? InternalPartNumberSelected { get; set; }
}

A list of such items ObservableCollection<BomLine> are displayed in a ListView. This works as expected. There is an additional binding on the value of InternalPartNumberSelected which gives the respective line a distinct color.

Now, when the value of InternalPartNumberSelected changes, no PropertyChanged event is fired (of course, there is no [ObservableProperty] or other explicit RaisePropertyChanged command.

I could now change the Scaffolded data to

public partial class BomLine : ObservableObject
{
    public int Id { get; set; }
    public int ProjectId { get; set; }
    public string? Manufacturer { get; set; }
    public string? ManufacturerPartNumber { get; set; }

    [ObservableProperty] string? _internalPartNumberSelected;
}

This would make the color change visible because now a Property Change event is fired and the Binding re-evalued.

Yet, this seems like a bad solution because it requires tinkering with scaffolded data (which would be overwritten).

Is there a "correct" approach to that problem? I'm using .net core 8 / efcore 8, WPF, MVVM toolkit.


Solution

  • You can keep separation of EF from view models by using an approach explained at https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/observableobject#wrapping-a-non-observable-model. In your case it would be something like this:

    public class BomLineViewModel : ObservableObject
    {
        private readonly BomLine model;
    
        public BomLineViewModel(BomLine model)
        {
            this.model = model;
        }
    
        public int Id
        {
            get => model.Id;
            // no setter, Id is readonly
        }
    
        public int ProjectId
        {
            get => model.ProjectId;
            set => SetProperty(model.ProjectId, value, model, (m, v) => m.ProjectId = v);
        }
    
        public string? Manufacturer
        {
            get => model.Manufacturer;
            set => SetProperty(model.Manufacturer, value, model, (m, v) => m.Manufacturer = v);
        }
    
        public string? ManufacturerPartNumber
        {
            get => model.ManufacturerPartNumber;
            set => SetProperty(model.ManufacturerPartNumber, value, model, (m, v) => m.ManufacturerPartNumber = v);
        }
    
        public string? InternalPartNumberSelected
        {
            get => model.InternalPartNumberSelected;
            set => SetProperty(model.InternalPartNumberSelected, value, model, (m, v) => m.InternalPartNumberSelected = v);
        }
    }
    

    That way you can add even other things to the view model and they won't affect EF.