MVVM公开列表从模型到视图模型和视图

时间:2019-02-01 20:57:58

标签: c# wpf mvvm

我有一个模型,该模型当前浏览一系列不同的日志文件,然后为这些文件中的每个项目创建一个对象,并将它们附加到列表(ListOfLogs)。模型解析完日志文件后,它将执行属性更改事件,以通知VM ListOfLogs已准备就绪。

然后,Viewmodel处理属性更改事件,并从模型的ListOfLogs创建一个ObservableCollection。然后,视图将绑定到该可观察的集合。

现在我已经从ObservableCollection切换到ICollectionView,因为调用线程不拥有ListOfLogs对象,所以我得到了无效的操作异常。这让我觉得我公开列表的方式不遵循MVVM模式

添加的代码: ViewModel.cs:

    public class ViewModel : INotifyPropertyChanged {
    #region Fields

    #endregion // Fields

    #region Properties

    public Model myModel { get; private set; }
    public ObservableCollection<MyObject> collectionView { get; set; }

    #endregion // Properties

    #region Constructor

    public ViewModel() {
        myModel = new Model();
        myModel.PropertyChanged += propertyChanged;
    }

    public event PropertyChangedEventHandler PropertyChanged;


    #endregion // Constructor

    #region Methods

    private void propertyChanged(object sender, PropertyChangedEventArgs e) {
        switch (e.PropertyName ) {
            case "Objects":
                // Is there a better way to do this

                collectionView = new ObservableCollection<MyObject>(myModel.Objects);

                //
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("collectionView"));
                break;
            default:
                Console.WriteLine(string.Format("No case for {0}, ", e.PropertyName));
                break;
        }
    }

Model.cs: 编辑:修复了调用属性更改事件时的错误

namespace TestApp1 {
public class Model : INotifyPropertyChanged {

    #region Fields

    private IList<MyObject> _Objects;

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion // Fields

    #region Properties

    public IList<MyObject> Objects { get => _Objects ?? (_Objects = new List<MyObject>()); private set { if (Objects != value) _Objects = value; } }

    #endregion // Properties

    #region Constructor

    public Model() {

    } 

    #endregion // Constructor

    #region Methods

    public void LoadObjects() {
        // Parse through files normally for now just junk works
        Parallel.For(0, 10000, dostuff => {
            var myOb = new MyObject(){ dt = DateTime.Now, message = "Message" };
            lock (Objects) {
                Objects.Add(myOb);
            }
        });
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Objects"));
    }

    #endregion // Methods

}

public class MyObject {
    public DateTime dt { get; set; }
    public string message { get; set; }
    public string stuff1 { get; set; }
    public string stuff2 { get; set; }
}

}

1 个答案:

答案 0 :(得分:0)

问题是,您正在修改对象列表,同时将其传递给可观察集合的构造函数。 (https://referencesource.microsoft.com/#system/compmod/system/collections/objectmodel/observablecollection.cs,cfaa9abd8b214ecb在构造函数中的“ copyfrom”中)

InvalidOperationException属于您在Parallel.For中的Objects.Add()调用。

private void CopyFrom(IEnumerable<T> collection)
        {
            IList<T> items = Items;
            if (collection != null && items != null)
            {
                using (IEnumerator<T> enumerator = collection.GetEnumerator())
                {
                    while (enumerator.MoveNext())
                    {
                        items.Add(enumerator.Current);
                    }
                }
            }
        }

在Parallel的委托中。因为您正在使用锁。您可以使用此以及该属性更改事件:


                    lock(myModel.Objects)
                    {

                    collectionView = new ObservableCollection<MyObject>(myModel.Objects);
                    }

或将引发事件添加到Parallel.For委托中的锁中

lock (Objects)
                    {
                        Objects.Add(myOb);
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Objects"));
                    }

或者您可以等到读取所有项目,然后在完成Parallel.For之后引发一个属性更改事件。