我有一个模型,该模型当前浏览一系列不同的日志文件,然后为这些文件中的每个项目创建一个对象,并将它们附加到列表(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; }
}
}
答案 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之后引发一个属性更改事件。