目前我在MVVM项目中有两个类:
Presenter
类,具有一个ObservableCollection<T>
和一个操作,用于从从Loader
类加载的项填充它;Loader
类本身,具有反序列化在给定目录中找到的文件的操作GetItems()
。
代码如下。
虽然文件加载是并行进行的,但我只能在加载所有文件后填充 ObservableCollection,这当然是一种糟糕的方法。
我的目标是将Populate
/GetItems
转换为在调用后立即返回的内容,并且加载的项目将在加载后立即在ObservableCollection中"弹出"。
我可以想到一些类似Parallel.ForEach
、IObservable
、事件的东西,但我不得不承认我对可能的替代方案感到非常迷茫。
class Presenter
{
public ObservableCollection<TVM> ItemsVM {get;}
= new ObservableCollection<TVM>();
public Loader _loader
= new Loader(some_well_known_directory_path);
void Populate()
{
foreach (T t_item in _loader.GetItems())
{
ItemsVM.Add(new TVM(t_item));
}
}
}
class Loader
{
readonly string _path;
public Loader(string path)
{
_path = path;
}
public IEnumerable<T> GetItems()
{
var result_list = new List<T>();
Parallel.ForEach(Directory.GetFiles(_path), fname =>
{
try
{
result_list.Add(T.Load(fname));
}
catch (Exception e)
{
logger.Warn(e.Message);
}
});
return result_list;
}
}
这正是Rx(System.Reactive)适合的情况。
试试这个:
class Presenter
{
public ObservableCollection<TVM> ItemsVM { get; }
= new ObservableCollection<TVM>();
public Loader _loader
= new Loader(some_well_known_directory_path);
void Populate()
{
_loader
.GetItems()
.Subscribe(t_item => ItemsVM.Add(new TVM(t_item)));
}
}
}
class Loader
{
readonly string _path;
public Loader(string path)
{
_path = path;
}
public IObservable<T> GetItems()
{
return
Observable
.Defer(() =>
Directory
.EnumerateFiles(_path)
.ToObservable()
.SelectMany(fname => Observable.Start(() => T.Load(fname)));
}
}