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

问题描述

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

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

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

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

约会视图模型.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
    }
}

约会页面.xaml:

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

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

因此,当执行命令时,创建的实体没有用户提供的值。(标题和日期仍然有它们的默认值)

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

标签: c#xamarin.formsmvvmentity-framework-core

解决方案


因此,当执行命令时,创建的实体没有用户提供的值。(标题和日期仍然有它们的默认值)

从您的代码中,您已经实现了 INotifyPropertyChanged,但您没有实现 viewmodel 的每个属性的所有设置器规则。您可以尝试根据以下代码修改您的代码。

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);
        }
    }

推荐阅读