【问题标题】:Entity Framework Core SQLite with Xamarin.Forms doesn't update Db带有 Xamarin.Forms 的 Entity Framework Core SQLite 不会更新 Db
【发布时间】:2020-08-09 18:59:30
【问题描述】:

我正在使用 Entity Framework Core SQLite 制作一个 Xamarin.Forms MVVM 应用程序,以在手机中本地保存一个 Db。

我生成了 Db 和一些初始项目,稍后通过 App 我添加了一个新项目,目前它工作正常(刷新 App 中的列表视图并正确显示所有项目)。

问题是当我想更新 Db 中的一项时。我更新了项目,但没有在列表视图中更新。它在列表视图中更新的唯一方法是重新启动 de App。

如何使用更新的项目刷新列表视图?

这是数据上下文代码:

public class DataContext : DbContext
{
    public DataContext() : base()
    {
        //Database.EnsureDeleted();
        Database.EnsureCreated();
    }

    public DbSet<Sensor> Sensors { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlite($"Filename={Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "database.sqlite")}");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Sensor>(s =>
        {
            s.HasKey(en => en.Id);
            //s.HasIndex(en => en.ClientId).IsUnique();
            s.Property(en => en.Name).IsRequired();
        });
        modelBuilder.Entity<Sensor>()
            .HasData(
                new Sensor { Id = Guid.NewGuid().ToString(), ClientId = "11111", Name = "First item", Description = "This is a private item description.", Payload = "Off" },
                new Sensor { Id = Guid.NewGuid().ToString(), ClientId = "11112", Name = "Second item", Description = "This is a shopping item description.", Payload = "Off" },
                new Sensor { Id = Guid.NewGuid().ToString(), ClientId = "11113", Name = "Third item", Description = "This is a work item description.", Payload = "Off" }
            );
    }

这是 MainPageViewModel 代码:

    public class MainPageViewModel : ViewModelBase
{
    private readonly INavigationService _navigationService;
    private readonly DataContext _dataContext;
    private static MainPageViewModel _instance;
    private DelegateCommand _addSensorCommand;
    private ObservableCollection<SensorItemViewModel> _sensors;

    public MainPageViewModel(
        INavigationService navigationService,
        DataContext dataContext) : base(navigationService)
    {
        _navigationService = navigationService;
        _dataContext = dataContext;
        _instance = this;
        LoadSensors();
    }

    public DelegateCommand AddSensorCommand => _addSensorCommand ?? (_addSensorCommand = new DelegateCommand(AddSensor));

    public ObservableCollection<SensorItemViewModel> Sensors
    {
        get => _sensors;
        set => SetProperty(ref _sensors, value);
    }

    public static MainPageViewModel GetInstance()
    {
        return _instance;
    }

    private async void AddSensor()
    {
        await _navigationService.NavigateAsync("SensorPage", null);
    }

    public async void LoadSensors()
    {
        try
        {
            var _sensors = await _dataContext.Sensors.ToListAsync();
            Sensors = new ObservableCollection<SensorItemViewModel>(_sensors.Select(s => new SensorItemViewModel(_navigationService)
            {
                Id = s.Id,
                ClientId = s.ClientId,
                Name = s.Name,
                Description = s.Description,
                Payload = s.Payload
            }).ToList());
        }
        catch (Exception ex)
        {
            await App.Current.MainPage.DisplayAlert("Error", ex.Message, "Aceptar");
        }
    }
}

这是 SensorPageViewModel 代码:

    public class SensorPageViewModel : ViewModelBase
{
    private readonly INavigationService _navigationService;
    private readonly DataContext _dataContext;
    private DelegateCommand _addCommand;
    private Sensor _sensor;
    private string _buttonText;

    public SensorPageViewModel(
        INavigationService navigationService,
        DataContext dataContext) : base(navigationService)
    {
        _navigationService = navigationService;
        _dataContext = dataContext;
    }

    public DelegateCommand AddCommand => _addCommand ?? (_addCommand = new DelegateCommand(Add));

    public string ButtonText
    {
        get => _buttonText;
        set => SetProperty(ref _buttonText, value);
    }

    public Sensor Sensor
    {
        get => _sensor;
        set => SetProperty(ref _sensor, value);
    }

    public override void OnNavigatedTo(INavigationParameters parameters)
    {
        base.OnNavigatedTo(parameters);

        if (parameters.Count >= 1)
        {
            var parameterSensor = parameters.GetValue<SensorItemViewModel>("Sensor");
            Sensor = new Sensor()
            {
                Id = parameterSensor.Id,
                ClientId = parameterSensor.ClientId,
                Name = parameterSensor.Name,
                Description = parameterSensor.Description,
                Payload = parameterSensor.Payload
            };
            Title = Sensor.Name;
            ButtonText = "Editar";
        }
        else
        {
            Sensor = new Sensor();
            Title = "Nuevo sensor";
            ButtonText = "Salvar";
        }
    }

    private async void Add()
    {
        if (ButtonText == "Editar")
        {
            ButtonText = "Salvar";
            Title = "Editar";

            return;
        }

        try
        {
            if (Title == "Editar")
            {
                _dataContext.Sensors.Update(Sensor);
                await _dataContext.SaveChangesAsync();
            }
            else
            {
                Sensor.Id = Guid.NewGuid().ToString();
                _dataContext.Sensors.Add(Sensor);
                await _dataContext.SaveChangesAsync();
            }
        }
        catch (Exception ex)
        {
            await App.Current.MainPage.DisplayAlert("Error", ex.Message, "Aceptar");

            return;
        }

        MainPageViewModel.GetInstance().LoadSensors();
        await _navigationService.GoBackAsync();          
    }
}

这是 SensorItemViewModel 代码:

public class SensorItemViewModel : Sensor
{
    private readonly INavigationService _navigationService;
    private DelegateCommand _selectSensorCommand;

    public SensorItemViewModel(INavigationService navigationService)
    {
        _navigationService = navigationService;
    }

    public DelegateCommand SelectSensorCommand => _selectSensorCommand ?? (_selectSensorCommand = new DelegateCommand(SelectSensor));

    private async void SelectSensor()
    {
        var parameters = new NavigationParameters
        {
            {"Sensor", this}
        };

        await _navigationService.NavigateAsync("SensorPage", parameters);
    }
}

【问题讨论】:

  • 你能把 SensorItemViewModel.cs 的代码也显示一下吗?
  • 添加了 SensorItemViewModel.cs 并将 List&lt;SensorItemViewModel&gt; 更改为 ObservableCollection&lt;SensorItemViewModel&gt;。更新值后刷新ListView,但不起作用。
  • 你需要提高 'INotifyCollectionChanged' 或者你可以使用 'ObservableCollection' 因为它实现了 'INotifyCollectionChanged'。

标签: c# entity-framework xamarin.forms


【解决方案1】:

我调试了程序流程,发现当我更新项目并将_dataContext保存在SensorViewModel中时,它不会出现在MainPageViewModel中。

将更新项保存在SensorViewModel我在名称中添加了Actualizado

但是当我在MainViewModel 中阅读 de _dataContext 时,它并没有出现:

当我添加一个新项目时,它可以正常工作,没有问题。

【讨论】:

    【解决方案2】:

    这里的问题不是 Xamarin.Forms 不更新数据库。当您关闭然后打开应用程序时,您说您可以看到更新后的值。这意味着该值已成功保存在数据库中。问题是 UI 不知道某些内容已更新。当您在 ObservableCollection 中添加/删除项目时,该集合会处理该问题,因为它会为您引发 OnPropertyChanged。但是,当您只是更新一个项目(更改它的一些属性)时,您需要告诉 UI 某些内容发生了变化。这是通过 INotifyPropertyChanged 接口完成的。

    请参阅here 了解 INotifyPropertyChanged

    最简单的实现是这样的:

    public class PropertyChangedViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    
        protected void SetValue<T>(ref T backingField, T value, [CallerMemberName] string propertyName = null)
        {
            if (EqualityComparer<T>.Default.Equals(backingField, value))
            {
                return;
            }
    
            backingField = value;
    
            OnPropertyChanged(propertyName);
        }
    }
    

    之后,您可以让您的 SensorItemViewModel.cs 继承自 PropertyChangedViewModel 并在需要时引发 PropertyChanged 事件。

    另一件事——你永远不应该用你的 ViewModel 类来继承数据库实体类。 MVVM 的想法与拥有两次相同的类完全不同。您的 SensorItemViewModel 应该有自己的属性,对于您想要在 UI 中动态更新的每个属性,您需要引发 PropertyChanged 事件。

    假设您只有一个属性(Name)并且您想要动态更改它。然后您的SensorItemViewModel 将如下所示:

    public class SensorItemViewModel : PropertyChangedViewModel
    {
        private string name;
    
        public string Name
        {
            get => name;
            set => SetValue(ref name, value);
        }
    }
    

    这里,每次Name属性改变时,都会调用SetValue方法,该方法会为你处理事件引发,通知UI名称需要改变/重绘。

    【讨论】:

    • 感谢您的回答。我正在使用带有 Prism Mvvm 的 Xamarin.Forms,在检查代码后我发现 OnPropertyChanged 包含在 ViewModelBase 中。我将创建一个基本的新项目来尝试找出错误。
    • 内置没关系。那就更好了。这里的解决方案是通知 UI 某处发生了变化,然后 UI 就会知道要重新渲染什么。在我们的新项目中使用 PropertyChanged,您将在 UI 中看到立即更新。
    【解决方案3】:

    我做了一个简单的应用程序来表达关心。

    该程序使用实体框架 SQLite Xamarin.Forms 和 Prism 与 MVVM

    这是 GitHub 的链接:

    Test EFSQLite

    【讨论】:

      猜你喜欢
      • 2020-04-28
      • 2021-12-02
      • 2018-04-12
      • 2017-02-15
      • 1970-01-01
      • 2017-09-17
      • 2017-10-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多