Mvvmcross 推迟PropertyChanged事件,直到视图绑定设置完成
我们的许多MVVMcross视图依赖远程服务来充分显示它们自己。我们通常在ViewModel的Init()中启动一个任务,以使其异步。ViewModel属性在任务完成时在任务中设置,UI通过PropertyChanged通知更新 有时,远程数据(和任务)在视图绑定其侦听器之前完成,因此不会收到属性更改事件 这个问题在上有涉及,但解决方案感觉像是演示逻辑的重复 在ViewDidLoad结束之前,我们已经成功地缓冲了PropertyChanged通知,但我们希望通过连接到MVX框架,将下面的解决方案转变为更通用的解决方案 有没有办法钩住mvvmcross的视图创建,以便在viewDidLoad完成后触发代码 基本视图模型Mvvmcross 推迟PropertyChanged事件,直到视图绑定设置完成,mvvmcross,Mvvmcross,我们的许多MVVMcross视图依赖远程服务来充分显示它们自己。我们通常在ViewModel的Init()中启动一个任务,以使其异步。ViewModel属性在任务完成时在任务中设置,UI通过PropertyChanged通知更新 有时,远程数据(和任务)在视图绑定其侦听器之前完成,因此不会收到属性更改事件 这个问题在上有涉及,但解决方案感觉像是演示逻辑的重复 在ViewDidLoad结束之前,我们已经成功地缓冲了PropertyChanged通知,但我们希望通过连接到MVX框架,将下面的解决方案
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();
}
}
}
公共抽象类BaseViewModel:MvxViewModel{
受保护的bool\u deferPropertyChangedEvents=true;
私有只读列表_deferedPropertyChangedEvents=新列表();
公共覆盖无效RaisePropertyChanged(PropertyChangedEventArgs changedArgs)
{
锁定(\u延迟属性更改){
如果(!\u延迟属性更改)
{
base.RaisePropertyChanged(changedArgs);
}
其他的
{
//缓冲
_延迟属性changedEvents.Add(changedArgs);
}
}
}
public void EndDeferringPropertyChangedEvents()
{
锁(_deferedPropertyChangedEvents){
_DelferPropertyChangedEvents=false;
//播放所有缓冲通知
foreach(递延属性变更中的变量e)
{
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();
}
}
public类SomeView:MvxViewController
{
公共覆盖无效ViewDidLoad()
{
base.ViewDidLoad();
var bindings=this.CreateBindingSet();
.....
bindings.Apply();
//回放缓冲的所有PropertyChanged()通知
//在视图初始化时启动
//-->是否要找到一种让MVX调用此函数的方法
ViewModel.EndDeferringPropertyChangedEvents();
}
}
作为一个简单的答案,我相信使用BaseViewModel
cast可以轻松调用您自己的线路:
// ---> want to find a way to have MVX call this
((BaseViewModel)ViewModel).EndDeferringPropertyChangedEvents();
然而,从更技术的角度来看,我认为进一步检查和理解为什么延迟代码是必要的可能是有用的,以便进一步了解底层线程问题是什么 目前有许多因素让我感到困惑:
bindings.Apply()期间
所有当前绑定的属性值应从视图模型
传输到视图
-因此调用EndDeferringPropertyChangedEvents()下一行中的code>应该(理论上)很少会得到不同的值
RaisePropertyChanged
方法将通知更改为跨UI线程。由于在UI线程上也会调用ViewDidLoad
,这意味着在ViewDidLoad
期间在后台线程上进行的任何RaisePropertyChanged
调用都应自动推迟到ViewDidLoad
完成且UI线程可用之后MvxNotifyPropertyChanged
代码,我能看到的唯一可能的差距是,多线程可能通过此自动RaisePropertyChanged
延迟找到一种方法,这就是此优化检查:
// check for subscription before potentially causing a cross-threaded call
if (PropertyChanged == null)
return;
(来自)Init
方法也在使用async
进行任务管理,则此async
代码也应使用UI线程-因此此异步操作的“回调”也应编组回UI线程(因此不应在ViewDidLoad
本身期间执行)正如我所说,这些因素让我感到困惑-我没有一个明确的答案/解释-抱歉!但我希望看到一个示例问题,并尝试在通用级别上帮助解决它。您的评论让我怀疑问题是由我们的代码中的某些内容引起的-我将进一步挖掘。感谢您对bindin的澄清g processGood luck。我仍然非常愿意接受这可能是一个普遍的问题的想法。多线程有办法找到逻辑上的漏洞。我还无法确定确切的原因,只发生在20次执行中的每一次,并且只出现在一个屏幕上。我们现在将使用我们的解决方法,稍后尝试找到原因。