Mvvmcross 推迟PropertyChanged事件,直到视图绑定设置完成

Mvvmcross 推迟PropertyChanged事件,直到视图绑定设置完成,mvvmcross,Mvvmcross,我们的许多MVVMcross视图依赖远程服务来充分显示它们自己。我们通常在ViewModel的Init()中启动一个任务,以使其异步。ViewModel属性在任务完成时在任务中设置,UI通过PropertyChanged通知更新 有时,远程数据(和任务)在视图绑定其侦听器之前完成,因此不会收到属性更改事件 这个问题在上有涉及,但解决方案感觉像是演示逻辑的重复 在ViewDidLoad结束之前,我们已经成功地缓冲了PropertyChanged通知,但我们希望通过连接到MVX框架,将下面的解决方案

我们的许多MVVMcross视图依赖远程服务来充分显示它们自己。我们通常在ViewModel的Init()中启动一个任务,以使其异步。ViewModel属性在任务完成时在任务中设置,UI通过PropertyChanged通知更新

有时,远程数据(和任务)在视图绑定其侦听器之前完成,因此不会收到属性更改事件

这个问题在上有涉及,但解决方案感觉像是演示逻辑的重复

在ViewDidLoad结束之前,我们已经成功地缓冲了PropertyChanged通知,但我们希望通过连接到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();
            }
        }
}
公共抽象类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()应该(理论上)很少会得到不同的值

  • 此外,默认的MvvmCross
    RaisePropertyChanged
    方法将通知更改为跨UI线程。由于在UI线程上也会调用
    ViewDidLoad
    ,这意味着在
    ViewDidLoad
    期间在后台线程上进行的任何
    RaisePropertyChanged
    调用都应自动推迟到
    ViewDidLoad
    完成且UI线程可用之后

  • 查看
    MvxNotifyPropertyChanged
    代码,我能看到的唯一可能的差距是,多线程可能通过此自动
    RaisePropertyChanged
    延迟找到一种方法,这就是此优化检查:

            // check for subscription before potentially causing a cross-threaded call
            if (PropertyChanged == null)
                return;
    
    (来自)

  • 如果ViewModel
    Init
    方法也在使用
    async
    进行任务管理,则此
    async
    代码也应使用UI线程-因此此异步操作的“回调”也应编组回UI线程(因此不应在
    ViewDidLoad
    本身期间执行)


  • 正如我所说,这些因素让我感到困惑-我没有一个明确的答案/解释-抱歉!但我希望看到一个示例问题,并尝试在通用级别上帮助解决它。

    您的评论让我怀疑问题是由我们的代码中的某些内容引起的-我将进一步挖掘。感谢您对bindin的澄清g processGood luck。我仍然非常愿意接受这可能是一个普遍的问题的想法。多线程有办法找到逻辑上的漏洞。我还无法确定确切的原因,只发生在20次执行中的每一次,并且只出现在一个屏幕上。我们现在将使用我们的解决方法,稍后尝试找到原因。