【问题标题】:MVVM Expose List from Model to ViewModel and View从模型到 ViewModel 和 View 的 MVVM 公开列表
【发布时间】:2019-02-01 20:57:58
【问题描述】:

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

Viewmodel 然后处理属性更改事件并从模型的 ListOfLogs 创建一个 ObservableCollection。然后视图绑定到该 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;
        }
    }

模型.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; }
}

}

【问题讨论】:

  • 您能否添加需要帮助的相关、最少的代码?
  • @ManojChoudhari 我很快就写了一些东西,并对我在 ViewModel.cs::propertyChanged 方法中询问的内容添加了评论。视图只是一个绑定到 VM 中属性的数据网格

标签: c# wpf mvvm


【解决方案1】:

问题是,您正在修改 Objects 列表,同时将它传递给 observable 集合的构造函数。 (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.For 的委托中,您正在使用锁。您也可以将其用于属性更改事件:


                    lock(myModel.Objects)
                    {

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

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

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

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

【讨论】:

  • 我的错,当我写这篇文章时,我在哪里引发了 Property changed 事件时犯了一个错误。在实际代码中,我按照您的建议在并行之外调用属性更改事件。我仍然得到相同的无效操作异常,但仅在使用 ICollectionView 而不是 ObservableCollection 时。否则 ObservableCollection 不会抛出任何异常
猜你喜欢
  • 1970-01-01
  • 2012-05-06
  • 1970-01-01
  • 1970-01-01
  • 2011-08-14
  • 2016-08-23
  • 2012-09-01
  • 2013-08-29
  • 2019-01-01
相关资源
最近更新 更多