我们的一些MVVMcross视图依赖于远程服务来完全显示自己。我们通常使用ViewModel的Init()中的任务来启动它以使其异步。 ViewModel属性在完成时在Task中设置,通过PropertyChanged通知更新UI。
有时远程数据(和任务)在View绑定它的侦听器之前完成,因此没有收到属性更改事件。
async Init and Property Changed in MvvmCross触及了这个问题,但解决方案感觉就像复制了表示逻辑。
我们已成功缓存PropertyChanged通知,直到ViewDidLoad结束,但我们想通过挂钩MVX框架将下面的内容变成更通用的解决方案。
有没有办法挂钩mvvmcross的视图创建,以便在viewDidLoad完成后关闭我们的代码?
基本视图模型
public abstract class BaseViewModel : MvxViewModel{
protected bool _deferPropertyChangedEvents = true;
private readonly List<PropertyChangedEventArgs> _deferedPropertyChangedEvents = new List<PropertyChangedEventArgs>();
public override void RaisePropertyChanged(PropertyChangedEventArgs changedArgs)
{
lock(_deferedPropertyChangedEvents){
if (!_deferPropertyChangedEvents)
{
base.RaisePropertyChanged(changedArgs);
}
else
{
// buffer it up
_deferedPropertyChangedEvents.Add(changedArgs);
}
}
}
public void EndDeferringPropertyChangedEvents()
{
lock(_deferedPropertyChangedEvents){
_deferPropertyChangedEvents = false;
// playback all buffered notifications
foreach (var e in _deferedPropertyChangedEvents)
{
RaisePropertyChanged(e);
}
_deferedPropertyChangedEvents.Clear();
}
}
}
示例视图
public class SomeView : MvxViewController
{
public override void ViewDidLoad()
{
base.ViewDidLoad();
var bindings = this.CreateBindingSet<StopView, SomeViewModel>();
.....
bindings.Apply();
// plays back any PropertyChanged() notifications that were buffered
// up while the view was initializing
// ---> want to find a way to have MVX call this
ViewModel.EndDeferringPropertyChangedEvents();
}
}
答案 0 :(得分:1)
作为一个简单的答案,我相信您可以使用BaseViewModel
演员轻松调用自己的专栏:
// ---> want to find a way to have MVX call this
((BaseViewModel)ViewModel).EndDeferringPropertyChangedEvents();
但是,在更技术性的说明中,我认为进一步检查和理解为什么需要这个Deferring
代码可能是有用的 - 进一步了解潜在的线程问题是什么。
目前有很多因素让我感到困惑::
在第bindings.Apply();
行中,所有当前绑定属性值都应从ViewModel
转移到View
- 因此调用EndDeferringPropertyChangedEvents();
在下一行应该(理论上)很少得到不同的值。
此外,默认的MvvmCross RaisePropertyChanged
方法将通知更改为UI线程。因为在UI线程上也调用ViewDidLoad
,这意味着RaisePropertyChanged
期间在后台线程上进行的任何ViewDidLoad
调用都应自动延迟,直到ViewDidLoad
完成后UI线程可用。
查看MvxNotifyPropertyChanged
代码,我可以看到mutli-threading可能通过此自动RaisePropertyChanged
延迟找到方法的唯一潜在差距在于此优化检查:
// check for subscription before potentially causing a cross-threaded call
if (PropertyChanged == null)
return;
如果您的ViewModel Init
方法也使用async
进行Task
管理,那么此async
代码也应该使用UI线程 - 所以此异步操作的“回调”也应该编组回UI线程(因此不应在ViewDidLoad
本身执行)。
正如我所说,这些因素令我感到困惑 - 我没有明确的答案/解释 - 抱歉!但是,我希望看到一个示例问题并尝试在通用级别帮助解决它。