2014-01-07 180 views
2

我們的一些MVVMcross視圖依賴於遠程服務來完全顯示自己。我們通常使用ViewModel的Init()中的任務來啓動它,使其異步。 ViewModel屬性在完成時在Task中設置,UI通過PropertyChanged通知更新。推遲PropertyChanged事件,直到視圖綁定設置完成

有時,遠程數據(和任務)在視圖綁定了偵聽器之前完成,因此沒有收到屬性更改事件。

這個問題在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(); 
     } 
    } 

回答

1

作爲一個簡單的答案,我相信自己的線可以很容易地使用BaseViewModel投被稱爲:

 // ---> want to find a way to have MVX call this 
     ((BaseViewModel)ViewModel).EndDeferringPropertyChangedEvents(); 

然而,在更多的技術說明中,我認爲進一步檢查和理解爲什麼這個代碼是必需的 - 以進一步研究底層線程問題是什麼。

有許多被我百思不得其解目前::

  1. 在行bindings.Apply();所有當前綁定屬性值應該從ViewModel轉移到View因素 - 因此調用EndDeferringPropertyChangedEvents();在下一行應該(理論上)很少得到不同的值。

  2. 此外,默認的MvvmCross RaisePropertyChanged方法將通知更改爲UI線程。由於ViewDidLoad也在UI線程上調用,這意味着在ViewDidLoad期間對後臺線程所做的任何RaisePropertyChanged調用都應自動延遲,直到ViewDidLoad完成並且UI線程變爲可用。

  3. 望着MvxNotifyPropertyChanged代碼,唯一的潛在間隙,我可以看到輯陣線程可能是通過這種自動RaisePropertyChanged推遲找到一種方法就是在這種優化檢查:

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

    (從https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross/ViewModels/MvxNotifyPropertyChanged.cs#L76

  4. 如果您的ViewModel Init方法也使用async進行管理,那麼這個async代碼也應該使用UI線程 - 所以此異步操作的「回調」也應編組回UI線程(因此不應在ViewDidLoad本身執行)。

正如我所說的,這些因素都令人困惑 - 我沒有一個明確的答案/解釋 - 對不起!但我很想看到一個示例問題,並試圖在通用層面幫助解決它。

+0

您的評論讓我懷疑問題是由我們的代碼中的某些東西引起的 - 我會多挖一點。感謝您澄清綁定過程 – geoffreys

+0

祝您好運。我仍然非常接受這個想法,這可能是一個普遍的問題。多線程有找到邏輯上的差距的方法。 – Stuart

+0

我沒有找到確切的原因,只發生在20次執行中的每一次,並且只在一個屏幕上發生。我們現在將使用我們的解決方法,並稍後嘗試查找原因。 – geoffreys

相關問題