当项目添加到模型 C# wpf 时更新 Observable 集合

Update Observable Collection When Item Added to Model C# wpf

好的,我对此还很陌生。我跟随了 YouTube 上的 this MVVM tutorial。这非常好而且简单明了。基本上,它设置了一个非常基本的程序,其中包含一个模型 class、DataAcess class、3 个视图模型(Main window、Employee 和 ViewModelBase),最后是一个具有堆栈面板和几个视图的视图绑定到模型中的 FirstName 和 LastName 的文本框。

一切都按预期运作,我已经经历了很多次,我很确定我理解这一切是如何运作的但我遇到的麻烦是增加新员工.

在 DataAccess class(员工信息库)中添加员工,如下所示。

    class EmployeeRepository
{
    readonly List<Employee> _employee;

    public EmployeeRepository()
    {
        if (_employee == null)
        {
            _employee = new List<Employee>();
        }

        _employee.Add(Employee.CreateEmployee("Bob", "Jones"));
        _employee.Add(Employee.CreateEmployee("Sarah", "Marshall"));
        _employee.Add(Employee.CreateEmployee("Peter", "Piper"));

    }

    public List<Employee> GetEmployees()
    {
        return new List<Employee>(_employee);
    }


}

并且在模型中有一个调用 CreateEmployee 的方法

    public class Employee
{
    public static Employee CreateEmployee(string firstName, string lastName)
    {

        return new Employee { FirstName = firstName, LastName = lastName };

    }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

所以我想我会在 MainWindow 中添加一个按钮,然后在列表中添加另一个名称。跳转视图将随着项目的更新而更新。只是为了看看它是否有效,我只是使用了后面的代码。

我想我可以像在 EmployeeRepository 中那样添加一个新员工,所以我尝试了这个

    readonly List<Employee> _employee = new List<Employee>();

    private void btnAdd_Click(object sender, RoutedEventArgs e)
    {
        _employee.Add(Employee.CreateEmployee("John", "Smith"));
    }

我试过很多方法都没有用。我看过并阅读了很多教程和问题,但我没有尝试过。

我错过了什么?我最初认为它不起作用,因为我将项目添加到存储库中的列表,而不是添加到视图模型中的 ObservableCollection。而 AllEmployees ObservableCollection 是视图的 ItemSource。

    readonly EmployeeRepository _employeeRepository;

    public ObservableCollection<Model.Employee> AllEmployees
    {
        get;
        private set;
    }

    public EmployeeListViewModel(EmployeeRepository currentWindowRepository)
    {
        if (currentWindowRepository == null)
        {
            throw new ArgumentException("currentWindowRepository");
        }
        _employeeRepository = currentWindowRepository;
        this.AllEmployees = new ObservableCollection<Model.Employee>(_employeeRepository.GetEmployees());
    }

但是在按钮代码中我试图实现类似的东西,但是没有。

我还可以添加视图 xaml 代码和 MainViewModel 代码,以便您可以根据需要查看它是如何绑定的。

在此先感谢您的帮助!

在您的 EmployeelistViewModel 中,您正在创建 ObservableCollection ,并且您认为它会在 addition/deletion 名员工上自动重新填充。其次,在您的 GetEmployees 方法中,您正在创建一个新列表。您应该直接使用 obser.coll 代替 List (_employee)。 return 这个 ocoll 来自你的方法。

您不能在 "one operation" 中执行此操作。

当您在 UI 中添加一个新的 Employee 时,您首先需要实例化您的 Employee class 并将其添加到可观察集合中。

如果处于有效状态,则将其保存到存储库中。

private ICommand addEmployeeCommand;
public ICommand AddEmployeeCommand { get { return addEmployeeCommand; } }

public ObservableCollection<Employee> Employees { get; protected set; }

private void AddEmployee() 
{
    // Get the user input that's bound to the viewmodels properties
    var employee = Employee.Create(FirstName, LastName);

    // add it to the observable collection
    // Note: directly using model in your ViewModel for binding is a pretty bad idea, you should use ViewModels for your Employees too, like: 
    // Employee.Add(new EmployeeViewModel(employee));
    Employees.Add(employee);

    // add it to the repository
    this.employeeRepository.AddOrUpdate(employee);
}

// in constructor
this.addEmployeeCommand = new DelegateCommand(AddEmployee, CanExecuteAddEmployee);

如前所述,避免在 ViewModel 绑定中直接使用您的模型,它有几个缺点,比如您现在的视图取决于您的视图模型。模型中的每个更改都需要反映在视图中,这超出了视图模型的目的,视图模型旨在解耦视图、视图模型和模型。

另一个缺点是,通常您的模型不会实现 INotifyPropertyChanged,这会导致视图中出现内存泄漏。

一个解决方案是将 INPC 添加到您的模型中,然后让您的视图模型观察他们的模型并相应地更新自己,即像这样:

public class MyListType
{
    // some data
}

public class MyModel
{
    public IList<MyListType> MyListItems { get; set; }

    public MyModel()
    {
        this.MyListItems = new ObservableCollection<MyListType>();
    }
}

public class MyListTypeViewModel : ViewModelBase
{
    public MyListType Model {get; set;}

    // INPC properties go here
}

public class MyViewModel
{
    public IList<MyListTypeViewModel> MyListItemViewModels { get; set; }

    public MyViewModel(MyModel model)
    {
        (model.MyListItems as INotifyCollectionChanged).CollectionChanged += OnListChanged;
        // todo: create initial view models for any items already in MyListItems
    }

    private void OnListChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        // create any new elements
        if (e.NewItems != null)
            foreach (MyListType item in e.NewItems)
                this.MyListItemViewModels.Add(new MyListTypeViewModel{Model = item});

        // remove any new elements
        if (e.OldItems != null)
            foreach (MyListType item in e.OldItems)
                this.MyListItemViewModels.Remove(
                    this.MyListItemViewModels.First(x => x.Model == item)
                );
    }

现在您的视图模型列表将自动与您的模型列表保持同步。这种方法的主要问题是您的模型通常源自您的 ORM(数据库)代码,因此您需要使用任何框架来在创建时注入 INPC,例如如果您使用的是 NHibernate,那么您需要使用 binding interceptor for INPC and a collection convention 来制作列表 ObservableCollections。