带有 EF Core 的 MVVM - 新实体作为命令参数,在视图模型中具有绑定属性

MVVM with EF Core - New entity as command parameter with bound properties in viewmodel

在 Xamarin.Forms 中深入研究了 MVVM 模式后,我将所有 ViewModel 函数包装到命令中,并从页面中的 XAML 调用它们。此外,我想通过我的命令确保可测试性,所以我将依赖项作为命令参数传递。

我有一个页面,可以在其中创建新实体并将其添加到 ef 核心数据库。

在用户将所有需要的值填入组件并设置 ViewModel 属性并单击页面按钮后,应将实体添加到数据库中。

代表所描述行为的我的代码:

AppointmentViewModel.cs:

public class AppointmentViewModel : INotifyPropertyChanged
{
    // Bound properties
    public string Title { get; set; }
    public DateTime Date { get; set; }

    // Command to add new appointment
    public ICommand AddAppointmentCommand { get; }

    // The appointment entity which will be passed as a command parameter
    public Appointment BoundAppointment => new Appointment(Title, Date);

    AppointmentViewModel()
    {
        AddAppointmentCommand = new Command<Appointment>(async a => await AddAppointment(a));
    }

    public async Task AddAppointment(Appointment appointment)
    {
        // Code to add an appointment to the database through Entity Framework core
    }
}

AppointmentPage.xaml:

<Button Command="{Binding AddAppointmentCommand}" CommandParameter="{Binding BoundAppointment}"/>

我目前面临的问题是 属性 BoundAppointment 只在页面打开时初始化,因此用户没有提供任何值。

所以当命令执行时,创建的实体没有user-supplied的值。 (标题和日期仍然是默认值)

我想将我的实体作为命令参数传递,但包含所有提供的值。 可悲的是,我没有找到解决方案,这可以确保我的命令的可测试性,例如。在单元测试中。

So when the command is executed, the created entity hasn't the values the user-supplied. (The Title and Date still have their default values)

根据您的代码,您已经实现了 INotifyPropertyChanged,但是您没有实现每个 属性 视图模型的所有 setter 规则。 您可以尝试根据以下代码修改您的代码。

public class AppointmentViewModel : INotifyPropertyChanged
{
    // Bound properties
    private string _Title;
    public string Title
    {
        get { return _Title; }
        set
        {
            _Title = value;
            RaisePropertyChanged("Title");
        }
    }
    private DateTime _Date;
    public DateTime Date
    {
        get { return _Date; }
        set
        {
            _Date = value;
            RaisePropertyChanged("Date");
        }
    }

    // Command to add new appointment
    public ICommand AddAppointmentCommand { get; }

    // The appointment entity which will be passed as a command parameter
    private Appointment _BoundAppointment;
    public Appointment BoundAppointment
    {
        get { return _BoundAppointment; }
        set
        {
            _BoundAppointment = new Appointment(Title, Date);
            RaisePropertyChanged("BoundAppointment");
        }
    }

    AppointmentViewModel()
    {
        AddAppointmentCommand = new Command<Appointment>(async a => await AddAppointment(a));
    }

    public async Task AddAppointment(Appointment appointment)
    {
        // Code to add an appointment to the database through Entity Framework core
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

更新:

当 Title 和 Date 值更改时,您可以更新 BoundAppointment

private string _Title;
    public string Title
    {
        get { return _Title; }
        set
        {
            _Title = value;
            RaisePropertyChanged("Title");
            BoundAppointment = new Appointment(Title, Date);
        }
    }
    private DateTime _Date;
    public DateTime Date
    {
        get { return _Date; }
        set
        {
            _Date = value;
            RaisePropertyChanged("Date");
            BoundAppointment = new Appointment(Title, Date);
        }
    }