對於客戶端應用程序而言,單頁應用程序(Single Page Application)是最多見的表現形式。有經驗的開發人員每每會把一個View分解多個SubView。那麼,如何在多個SubView之間 『共享數據』 是一個很棘手的事情。又由於ViewModel纔是真正爲View提供數據來源,因此本質上『共享數據』指的是多個ViewModel之間共享同一塊數據控件。javascript
談到『共享』兩字,腦海裏跳出第一個印象就是『繼承』。對吧,由於你是父母的孩子,因此理所固然你能夠和父母共享家中的一切。因此『共享』的前提,就是構建一個『繼承鏈』,也就是JavaScript中的『原型鏈』。java
那麼JavaScript是怎樣實現原型鏈呢?有經驗的JavaScript程序員想必早就記的倒背如流了——經過內置屬性 __proto__ 來實現。git
因此ViewModel之間『共享數據』的核心就是如何去實現一個繼承鏈,以下所示:程序員
有了上述的分析以後,只要仿照JavaScript的 __proto__ 的實現,咱們對全部ViewModel的基類ViewModelBase添加一個ParentViewModel 屬性,它表明當前ViewModel的父親對象。github
public class ViewModelBase
{
public ViewModelBase ParentViewModel { get; set; }
//...
}複製代碼
接着我參考了WPF中是怎樣獲取父ViewModel當中的數據:this
Binding="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}, Path=DataContext.ParentViewModelProperty}複製代碼
能夠看到經過 FindAncestor 方法,去指定 AncestorType 類型的上層對象中獲取數據。spa
因此,我爲ViewModelBase 增長一個擴展方法,能夠經過繼承鏈實現從指定的祖先對象獲取數據。code
public static IEnumerable<T> Ancestors<T>(this ViewModelBase origin) where T : ViewModelBase
{
if (origin==null)
{
yield break;
}
var parentViewModel = origin.ParentViewModel;
while (parentViewModel!=null)
{
var castedViewModel = parentViewModel as T;
if (castedViewModel != null)
{
yield return castedViewModel;
}
parentViewModel = parentViewModel.ParentViewModel;
}
}複製代碼
對應在ViewModel中,能夠經過 Ancestors擴展方法獲取上層對象的數據cdn
var ancestors = this.Ancestors<FaceBoxViewModel>();複製代碼
最後,以圖示的形式會更加直觀,下圖所示,SubViewModel依靠繼承鏈能夠輕鬆訪問到ParentViewModel的共享數據:xml
本篇文章介紹了怎樣在ViewModel之間共享數據,實際上解決方案是很是簡單的,人爲的構造了一個繼承鏈並隨着繼承鏈往上找,老是能找到但願獲取到的數據。相似與JavaScript中的原型鏈,維護了一種至上而下的父子關係。
源代碼託管在Github上,點擊此瞭解
歡迎關注個人公衆號: