天天看點

Caliburn.Micro 協定ViewViewModelBinder

協定是CM的一個主要特性,也是CM和其他MVVM架構最大的不同之處。利用協定可以完全把UI和邏輯分離,很多人都喜歡協定,但是也有一些人不喜歡,是以在CM中,協定是可以關閉的,當然預設是開啟的。

在這裡我們隻講ViewModel-First方式。

View

CM一開始就會根據ViewModel查找對應的View,怎麼查找呢?通過如下方式:

var viewTypeName = modelType.FullName.Replace("Model", string.Empty);
    if(context != null)
    {
        viewTypeName = viewTypeName.Remove(viewTypeName.Length - 4, 4);
        viewTypeName = viewTypeName + "." + context;
    }
           

即删除VM全名中所有的Model字元串,如果有context則在尾部增加.context。完整代碼在LocateForModelType方法中,有興趣的話可以檢視源代碼。我們暫時還用不到context,隻有多個view關聯一個ViewModel時才會用到,本文後邊會介紹。

ViewModelBinder

CM在找到比對的ViewModel和View後會調用ViewModelBinder關聯兩者。ViewModelBinder會把View的Action.Target設定為對應的ViewModel,還會把View的DataContext設定為對應的ViewModel。ViewModelBinder也會檢查ViewModel是否繼承了IviewAware,如果繼承了就會把View傳遞給IviewAware(也就是ViewModel)。然後它會建立兩者之間的屬性和action綁定。

ViewModelBinder查找wpf元素方法

ViewModelBinder是通過周遊VisualTree從View中查找能夠和VM中屬性方法綁定的元素的。ViewModelBinder可以在WPF中查找ContentControl.Content、ItemsControl.Items、HeaderContentControl.Header、HeaderedItemsControl.Header等。但是ContextMenus, Tooltips等是不能夠查找的,也就是說這些是不能應用協定的。

當然如果你想讓CM協定支援ContextMenus等,也不是沒有辦法,需要自定義。在xaml被編譯後,每一個有x:Name的元素都會生成一個private field,是以可以通過反射查找每一個field來實作,然後重寫GetNamedElementsInScope方法。CM之是以沒有實作是因為Silverlight因為安全問題不允許這樣做。

另外

在所有平台上,協定不能直接在DataTemplate上起作用。為了解決這個問題,需要在DataTemplate内的根元素上添加一個Bind.Model="{Binding}"附加屬性。

繼續閱讀