C# WPF MVVM开发框架Caliburn.Micro 关于Conventions⑧
01
—
關于Conventions
Caliburn.Micro的一個主要特性是,它能夠通過一系列約定消除對鍋爐銘牌代碼的需求。有些人喜歡習俗,有些人討厭習俗。這就是為什么CM的約定是完全可定制的,如果不需要,甚至可以完全關閉。如果您要使用約定,并且由于它們在默認情況下處于啟用狀態,那么最好了解這些約定是什么以及它們是如何工作的。這就是本文的主題。
View Resolution (ViewModel-First)
視圖分辨率(視圖模型優先)
基礎
使用CM時可能遇到的第一個約定與視圖分辨率有關。此約定影響應用程序的任何ViewModel優先區域。在ViewModel First中,我們有一個需要渲染到屏幕上的現有ViewModel。為此,CM使用一個簡單的命名模式來查找UserControl1,它應該綁定到ViewModel并顯示它。那么,這種模式是什么?讓我們看一下ViewLocator.LocateForModelType以了解:
public static Func<Type, DependencyObject, object, UIElement> LocateForModelType = (modelType, displayLocation, context) =>{var viewTypeName = modelType.FullName.Replace("Model", string.Empty);if(context != null){viewTypeName = viewTypeName.Remove(viewTypeName.Length - 4, 4);viewTypeName = viewTypeName + "." + context;}var viewType = (from assmebly in AssemblySource.Instancefrom type in assmebly.GetExportedTypes()where type.FullName == viewTypeNameselect type).FirstOrDefault();return viewType == null? new TextBlock { Text = string.Format("{0} not found.", viewTypeName) }: GetOrCreateViewType(viewType); };讓我們先忽略“context”變量。為了導出視圖,我們假設您在vm的命名中使用了文本“ViewModel”,因此我們只需通過刪除單詞“Model”將其更改為“view”。這具有更改類型名稱和名稱空間的效果。因此ViewModels.CustomerViewModel將成為Views.CustomerView。或者,如果您是按功能組織應用程序:CustomerManagement.CustomerServiceWModel變為CustomerManagement.CustomerView。希望這是非常直截了當的。獲得名稱后,我們將搜索具有該名稱的類型。我們將通過AssemblySource.Instance搜索您向CM公開的任何程序集。2如果我們找到類型,我們將創建一個實例(如果已注冊,則從IoC容器中獲取一個實例),并將其返回給調用方。如果找不到類型,我們將生成一個帶有適當“not found”消息的視圖。
現在,回到“上下文”值。這就是CM如何支持同一ViewModel上的多個視圖。如果提供了上下文(通常是字符串或枚舉),我們將根據該值對名稱進行進一步轉換。通過從末尾刪除單詞“View”并附加上下文,此轉換有效地假設您擁有用于不同視圖的文件夾(命名空間)。因此,給定“Master”上下文,我們的ViewModels.CustomerViewModel將變成Views.Customer.Master。
其他需要知道的事情
除了實例化視圖外,GetOrCreateViewType還將在視圖上調用InitializeComponent(如果存在)。這意味著,對于由ViewLocator創建的視圖,根本不需要代碼落后。如果這讓您感到高興,您可以刪除它們:)您還應該知道ViewLocator.LocateForModelType從不直接調用。它總是通過ViewLocator.LocateForModel間接調用。LocateForModel獲取ViewModel的實例并返回視圖的實例。LocateForModel的功能之一是檢查ViewModel是否實現了IViewAware。如果是這樣,它將調用它的GetView方法來查看您是否有緩存的視圖,或者是否顯式地處理視圖創建。如果不是,則將ViewModel的類型傳遞給LocateForModelType。
定制
開箱即用的約定非常簡單,它基于我們在現實世界中使用過和看到其他人使用過的許多模式。然而,您絕不局限于這些簡單的模式。您會注意到上面討論的所有方法都是作為Funcs實現的,而不是實際的方法。這意味著您可以通過簡單地用自己的實現替換它們來定制它們。如果只想添加到現有行為,只需將現有Func存儲在變量中,創建一個調用舊函數的新Func,然后將新Func分配給ViewLocator.LocateForModelType。
v1.1的更改v1.1中我們完全更改了LocateForModelType函數的實現。現在,我們使用新的NameTransformer類的一個實例以及預先配置的基于RexEx的規則來進行名稱映射。我們支持與以前相同的現成約定,但現在您可以更輕松地添加自定義轉換規則。
框架使用
框架使用ViewLocator的地方有三個;您可以期望應用視圖位置約定的三個位置。第一名是Bootstrapper。在這里,您的根ViewModel被傳遞給定位器,以確定應用程序的shell應該如何呈現。在Silverlight中,這將導致設置或您的RootVisual。在WPF中,這將創建主窗口。事實上,在WPF中,引導程序將此委托給WindowManager,這使我想到……ViewLocator使用的第二個位置是WindowManager,它調用它來確定任何對話框ViewModels應如何呈現。利用這些約定的第三個也是最后一個地方是View.Model attached屬性。每當您使用UIElement上的View.Model attached屬性進行ViewModel首次合成渲染時,都會調用定位器以查看合成的ViewModel應如何在UI中的該位置進行渲染。您可以在UI中顯式使用View.Model attached屬性(可以選擇將其與View.Context attached屬性組合以進行上下文呈現),也可以按約定添加該屬性,從而實現視圖的常規組合。請參閱下面關于屬性綁定約定的部分。
ViewModel Resolution (View-First)
視圖模型分辨率(視圖優先)
基礎
盡管Caliburn.Micro更喜歡ViewModel-First開發,但有時您可能希望采用視圖優先的方法,尤其是在使用WP7時。如果從視圖開始,則可能需要解析ViewModel。我們在這個場景中使用了與視圖位置類似的命名約定。這由ViewModelLocator.LocateForViewType處理。當使用視圖位置時,我們將“ViewModel”的實例更改為“View”,而使用ViewModel位置時,我們將“View”更改為“ViewModel”。另一個有趣的區別在于我們如何獲得ViewModel本身的實例。由于ViewModels可能由接口或具體類注冊,因此我們也嘗試生成可能的接口名稱。如果我們找到匹配項,我們將從IoC容器中解析它。
其他需要知道的事情
實際上,框架從未直接調用ViewModelLocator.LocateForViewType。它由ViewModelLocator.LocateForView在內部調用。LocateForView首先檢查視圖實例的DataContext,查看您以前是否緩存或自定義創建了ViewModel。如果DataContext為null,則只有在該情況下才會調用LocateForViewType。最后要注意的是,自動初始化組件調用在性質上不受view first支持。
定制
在v1.1中,我們完全改變了LocateForViewType函數的實現。現在,我們使用新的NameTransformer類的一個實例以及預先配置的基于RexEx的規則來進行名稱映射。我們支持與以前相同的現成約定,但現在您可以更輕松地添加自定義轉換規則。
框架使用
ViewModelLocator僅由框架的WP7版本使用。FrameAdapter使用它,它確保每次導航到頁面時,都提供了正確的ViewModel。如果需要的話,它可以很容易地適應Silverlight導航框架的使用。
ViewModelBinder
基礎
當我們將視圖和ViewModel綁定在一起時,無論是使用ViewModel優先還是視圖優先方法,都會調用ViewModelBinder.bind方法。此方法將視圖的Action.Target設置為ViewModel,并相應地將DataContext設置為相同的值。4它還檢查ViewModel是否實現了IViewAware,如果實現了,則將視圖傳遞給ViewModel。如果更適合您的場景,這將允許更具監督性的控制器樣式設計。ViewModelBinder所做的最后一件重要事情是確定是否需要創建任何常規屬性綁定或操作。為此,它在UI中搜索綁定/操作的候選元素列表,并將其與ViewModel的屬性和方法進行比較。當找到匹配項時,它將代表您創建綁定或操作。
其他需要知道的事情
在所有平臺上,約定都不能應用于DataTemplate的內容。這是Xaml模板系統的當前限制。我已經要求微軟解決這個問題,但我懷疑他們是否會回應。因此,為了將綁定和操作約定應用于DataTemplate,必須將Bind.Model=“{Binding}”附加屬性添加到DataTemplate內的根元素。這為Caliburn.Micro提供了必要的鉤子,以便在每次從DataTemplate實例化UI時應用其約定。
在WP7平臺上,如果要綁定的視圖是PhoneApplicationPage,則此服務負責將操作連接到ApplicationBar的按鈕和菜單。有關這方面的更多信息,請參閱WP7特定文檔。
定制
如果您決定不喜歡ViewModelBinder的行為(更多細節見下文),它將遵循與上述框架服務相同的模式。它有幾個函數,您可以用自己的實現來替換,例如Bind、BindActions和BindProperties。不過,定制最重要的方面可能是能夠關閉活頁夾的約定功能。為此,請將ViewModelBinder.ApplyConventionsByDefault設置為false。如果要逐個視圖啟用它,可以在視圖中將view.ApplyConventions attached屬性設置為true。此附加屬性以兩種方式工作。因此,如果默認情況下啟用了約定,但需要逐個視圖將其禁用,則只需將此屬性設置為false。
框架使用
ViewModelBinder用于Caliburn.Micro內部的三個位置。第一個位置是View.Model附加屬性的實現內部。此屬性獲取您的ViewModel,使用ViewLocator定位視圖,然后將它們一起傳遞到ViewModelBinder。綁定完成后,視圖被注入到定義屬性的元素中。這是ViewModel的第一個使用模式。使用ViewModelBinder的第二個位置是Bind.Model attached屬性的實現內部。此屬性獲取ViewModel并將其與定義該屬性的元素一起傳遞到ViewModelBinder。換言之,這是視圖優先,因為您已經在Xaml中內聯實例化了視圖,然后只是針對ViewModel調用綁定。使用ViewModelBinder的最后一個位置是框架的WP7版本。在FrameAdapter內部,當頁面被導航到時,首先使用ViewModelLocator獲取該頁面的ViewModel。然后,使用ViewModelBinder將ViewModel連接到頁面。
Element Location
基礎
現在,您已經了解了ViewModelBinder的基本角色以及框架使用它的位置,我想深入了解它如何應用約定的細節。如上所述,ViewModelBinder“在UI中搜索綁定/操作的候選元素列表,并將其與ViewModel的屬性和方法進行比較。”了解其工作原理的第一步是了解框架如何確定UI中哪些元素可能是約定的候選元素。它通過在名為GetNamedElementsInScope的靜態ExtensionMethods類上使用func來實現這一點。5基本上,該方法有兩個功能。首先,它確定了要在其中搜索元素的范圍。這意味著它將遍歷樹,直到找到合適的根節點,例如窗口、UserControl或沒有父節點的元素(表示我們在DataTemplate中)。一旦定義了作用域的“外部”邊界,它就開始了第二項任務:定位該作用域中具有名稱的所有元素。搜索會小心地遵守“內部”范圍邊界,不遍歷子用戶控件的內部。然后,ViewModelBinder使用此函數返回的元素應用約定。
其他需要知道的事情
GetNamedElementsInScope方法可以完成一些開箱即用的限制。它只能搜索可視化樹ContentControl.Content和ItemsControl.Items。在WPF中,它還搜索HeaderContentControl.Header和HeaderEditsControl.Header。這意味著,當嘗試應用約定時,將找不到上下文菜單、工具提示或任何其他不在可視化樹中或這些特殊位置之一的內容。
定制
您可能不會遇到與上述元素位置限制相關的問題。但是如果您這樣做了,您可以輕松地用自己的實現替換默認實現。您可能會選擇使用以下一種有趣的技術:如果視圖是用戶控件或窗口,則不必遍歷元素樹,而是使用一些反射來發現從FrameworkElement繼承的所有私有字段。我們知道,在編譯Xaml文件時,會為所有具有x:Name的文件創建一個私有字段。利用這個優勢。不過,您必須回到DataTemplateUI的現有實現。我不提供這種開箱即用的實現,因為它不能保證在Silverlight中成功。原因是Silverlight不允許您獲取私有字段的值,除非調用代碼是定義字段的代碼。但是,如果所有視圖都是在單個程序集中定義的,那么可以通過在與視圖相同的程序集中創建新實現來輕松地進行我剛才描述的修改。此外,如果您有一個多程序集項目,您可以編寫一點管道代碼,讓GetNamedElementsInScope funct找到可以實際執行反射的特定于程序集的實現。
框架使用
我已經提到,當ViewModelBinder嘗試按約定綁定屬性或方法時,會出現元素位置。但是,還有第二個地方使用此功能:解析器。每當您使用Message.Attach并且您的操作包含參數時,消息解析器必須找到您用作參數輸入的元素。看起來我們可以只做一個簡單的FindName,但是FindName是區分大小寫的。因此,我們必須使用自定義實現,它執行不區分大小寫的搜索。這確保了在兩個地方使用相同的綁定語義。
Action Matching
基礎
在找到約定綁定的元素后,ViewModelBinder要做的下一件事是檢查它們是否與ViewModel上的方法匹配。它通過使用一些反射來獲得ViewModel的公共方法來實現這一點。然后它在它們上面循環,尋找與元素匹配的不區分大小寫的名稱。如果找到匹配項,并且元素上沒有任何預先存在的Interaction.Triggers,則會附加一個操作。檢查預先存在的觸發器用于防止約定系統創建與開發人員在標記中明確聲明的操作重復的操作。為了安全起見,如果您在匹配的元素上聲明了任何觸發器,那么將跳過它。
其他需要知道的事情
常規操作是通過在元素上設置Message.Attach attached屬性創建的。讓我們看看這是如何建立起來的:
var message = method.Name; var parameters = method.GetParameters();if(parameters.Length > 0) {message += "(";foreach(var parameter in parameters){var paramName = parameter.Name;var specialValue = "$" + paramName.ToLower();if(MessageBinder.SpecialValues.Contains(specialValue))paramName = specialValue;message += paramName + ",";}message = message.Remove(message.Length - 1, 1);message += ")"; }Log.Info("Added convention action for {0} as {1}.", method.Name, message); Message.SetAttach(foundControl, message);如您所見,我們構建了一個表示消息的字符串。此字符串僅包含消息的操作部分;未聲明任何事件。您還可以看到,它循環遍歷方法的參數,以便將它們包含在操作中。如果參數名與一個特殊的參數值相同,我們確保將“$”附加到它,以便解析器能夠正確識別它,之后調用操作時MessageBinder能夠正確識別它。
設置Message.Attach屬性后,解析器立即啟動,將字符串消息轉換為某種類型的TriggerBase,其中包含關聯的ActionMessage。因為我們沒有將事件聲明為消息的一部分,所以解析器會查找消息所附加到的元素類型的默認觸發器。例如,如果消息被附加到一個按鈕,那么我們將得到一個EventTrigger,其事件設置為Click。此信息通過ConventionManager配置,具有合理的現成默認值。請參閱下面有關ConventionManager和ElementConventions的部分以了解更多信息。ElementConvention用于創建觸發器,然后解析器將操作信息轉換為ActionMessage。這兩個元素連接在一起,然后添加到Interaction.Triggers元素的集合中。
定制
ViewModelBinder.BindActions是一個Func,因此如果需要,可以完全替換。通過ConventionManager添加或更改ElementConventions也會影響操作的組合方式。下面將詳細介紹。
框架使用
BindActions僅由ViewModelBinder使用。
Property Matching
基礎
一旦動作綁定完成,我們就轉到屬性綁定。它遵循類似的過程,在命名元素中循環,并在屬性上查找不區分大小寫的名稱匹配項。一旦找到匹配項,我們就可以從ConventionManager獲取ElementConventions,這樣我們就可以確定該元素上的數據綁定方式。ElementConvention定義了一個ApplyBinding Func,它接受視圖模型類型、屬性路徑、屬性信息、元素實例和約定本身。此Func負責使用提供的所有上下文信息在元素上創建綁定。最妙的是,如果需要,我們可以為每個元素定制綁定行為。CM為ConventionManager上的大多數元素定義了ApplyBinding的基本實現。這叫做挫折,看起來像這樣:
public static Func<Type, string, PropertyInfo, FrameworkElement, ElementConvention, bool> SetBinding =(viewModelType, path, property, element, convention) => {var bindableProperty = convention.GetBindableProperty(element);if(HasBinding(element, bindableProperty))return false;var binding = new Binding(path);ApplyBindingMode(binding, property);ApplyValueConverter(binding, bindableProperty, property);ApplyStringFormat(binding, convention, property);ApplyValidation(binding, viewModelType, property);ApplyUpdateSourceTrigger(bindableProperty, element, binding);BindingOperations.SetBinding(element, bindableProperty, binding);return true;};此方法所做的第一件事是通過調用ElementConvention上的GetBindableProperty來獲取應該綁定的依賴項屬性。接下來,我們檢查該屬性是否已經存在綁定集。如果有,我們不想覆蓋它。開發人員可能在這里做了一些特殊的事情,因此我們返回false,表示尚未添加綁定。假設不存在綁定,該方法基本上會委托ConventionManager上的其他方法來獲取綁定應用程序的詳細信息。希望這一部分有意義。一旦綁定被完全構造,我們將其添加到元素中,并返回true,指示應用了約定。
屬性匹配還有另一個重要方面,我還沒有提到。我們也可以通過約定在深層屬性路徑上進行匹配。因此,假設您的ViewModel上有一個Customer屬性,它有一個FirstName屬性,您希望將文本框綁定到該屬性。只需給文本框一個x:Name“Customer_FirstName”,ViewModelBinder將完成所有工作以確保該屬性有效,并將正確的視圖模型類型、屬性信息和屬性路徑傳遞給ElementConvention的ApplyBinding函數。
其他需要知道的事情
我在上面提到,“CM為大多數元素定義了ApplyBinding的基本實現。”它還為通常與特定使用模式或組合關聯的元素定義了ApplyBinding Func的幾個自定義實現。對于WPF和Silverlight,ItemsControl和Selector具有自定義綁定行為。除了在ItemsControl上綁定ItemsSource外,ApplyBinding函數還檢查ItemTemplate、DisplayMemberPath和ItemTemplateSelector(WPF)屬性。如果這些都沒有設置,那么框架就會知道,由于您沒有為項目指定呈現器,它應該按常規添加一個。7因此,我們將ItemTemplate設置為默認DataTemplate。下面是它的樣子:
<DataTemplate xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:cal="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro"><ContentControl cal:View.Model="{Binding}" VerticalContentAlignment="Stretch"HorizontalContentAlignment="Stretch" /> </DataTemplate>由于此模板創建了一個帶有View.Model附加屬性的ContentControl,因此我們為ItemsControl創建了豐富組合的可能性。因此,無論項目是什么,View.Model attached屬性都允許我們調用ViewModel First工作流:找到項目的視圖,將項目和視圖傳遞給ViewModelBinder(ViewModelBinder反過來設置自己的約定,可能會調用更多組合),然后獲取視圖并將其注入ContentControl。選擇器的行為與ItemsControl相同,但在SelectedItem屬性周圍有一個附加約定。假設您的選擇器稱為Items。我們首先遵循上述約定,將ItemsSource綁定到Items,并檢測是否需要添加默認的DataTemplate。然后,檢查SelectedItem屬性是否已綁定。如果沒有,我們將在ViewModel上查找可以綁定到SelectedItem的三個候選屬性:ActiveItem、SelectedItem和CurrentItem。如果找到其中一個,我們將添加綁定。因此,這里的模式是,我們首先調用ConventionManager.Singularize來指定集合屬性的名稱。在這種情況下,“Items”變為“Item”,然后我們稱ConventionManager.DerivePotentialSelectionNames,它在“Active”、“Selected”和“Current”前面加上“Active”和“Current”以使上述三個候選項成為“Item”。然后,如果在ViewModel上找到其中一個,我們將創建一個綁定。對于WPF,我們為TabControl提供了一個特殊的ApplyBinding行為。8它采用選擇器的所有約定(將其ContentTemplate而不是ItemTemplate設置為DefaultDataTemplate),并為選項卡標題的內容提供了一個附加約定。如果未設置TabControl的DisplayMemberPath,并且ViewModel實現IHaveDisplayName,則我們將其ItemTemplate設置為DefaultHeaderTemplate,如下所示:
<DataTemplate xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"><TextBlock Text="{Binding DisplayName, Mode=TwoWay}" /> </DataTemplate>因此,對于命名的WPF TabControl,我們可以常規地在選項卡列表(ItemsSource)中綁定選項卡項的名稱(ItemTemplate)、每個選項卡的內容(ContentTemplate),并保持所選選項卡與模型同步(SelectedItem)。對于這樣一行Xaml來說,這還不錯:
<TabControl x:Name="Items" />除了上面列出的特殊情況外,我們還有一個很重要的問題:ContentControl。在本例中,我們不提供自定義ApplyBinding函數,但提供自定義GetBindableProperty函數。對于ContentControl,當我們決定綁定到哪個屬性時,我們檢查ContentTemplate和ContentTemplateSelector(WPF)。如果它們都為null,則表示尚未為模型指定渲染器。因此,我們假設您希望使用ViewModel First工作流。我們通過讓GetBindableProperty函數返回View.Model attached屬性作為要綁定的屬性來實現這一點。在所有其他情況下,ContentControl將綁定到Content屬性。通過在沒有ContentTemplate的情況下選擇View.Model屬性,我們可以實現豐富的合成。
我希望當你思考這些特殊情況時,你會發現它們是有道理的。一如既往,如果你不喜歡它們,你可以改變它們…
定制
正如您所想象的,通過替換ViewModelBinder上的Func,BindProperties功能完全可以自定義。例如,如果你喜歡動作約定而不是屬性約定,你可以用一個不做任何事情的Func替換這個Func。然而,您可能需要更細粒度的控制。幸運的是,ConventionManager或特定ElementConvention的幾乎每個方面都是可定制的。有關ConventionManager的更多詳細信息如下。
配置約定的常用方法之一是向系統中添加新約定。最常見的情況是添加Silverlight toolkit控件或WP7 toolkit控件。下面是一個示例,說明如何為WP7 Pivot控件設置一個高級約定,使其與WPF TabControl類似:
ConventionManager.AddElementConvention<Pivot>(Pivot.ItemsSourceProperty, "SelectedItem", "SelectionChanged").ApplyBinding =(viewModelType, path, property, element, convention) => {ConventionManager.GetElementConvention(typeof(ItemsControl)).ApplyBinding(viewModelType, path, property, element, convention);ConventionManager.ConfigureSelectedItem(element, Pivot.SelectedItemProperty, viewModelType, path);ConventionManager.ApplyHeaderTemplate(element, Pivot.HeaderTemplateProperty, viewModelType);};很酷吧?
框架使用
BindProperties僅由ViewModelBinder使用。
會議經理
如果您已經閱讀了本文,您就會知道ConventionManager在很大程度上受到操作和屬性綁定機制的影響。它是微調框架中大多數約定行為的網關。以下是可用于自定義框架約定的可替換函數和屬性的列表:
性質
BooleantVisibilityConverter–用于將布爾值轉換為可見性并返回的默認IValueConverter。由ApplyValueConverter使用。
IncludeStaticProperties-指示在約定名稱匹配期間是否應包括靜態屬性。默認情況下為False。
DefaultItemTemplate–當ItemsControl或ContentControl需要DataTemplate時使用。
DefaultHeaderTemplate–當TabControl需要標題模板時,由ApplyHeaderTemplate使用。
芬克斯
單數化–將單詞從復數形式轉換為單數形式。默認的實現是非常基本的,只是去掉了后面的's'。
DerivePotentialSelectionNames–給定基本集合名稱,返回表示所選內容的可能屬性名稱列表。使用Singularize。
SetBinding–ElementConventions使用的ApplyBinding的默認實現(更多信息見下文)。更改此選項將更改所有常規綁定的應用方式。在內部使用以下函數:
HasBinding—確定特定依賴項屬性是否已在提供的元素上具有綁定。如果綁定已存在,則SetBinding將中止。
ApplyBindingMode-將適當的綁定模式應用于綁定。
ApplyValidation—確定是否以及在綁定上啟用何種類型的驗證。
ApplyValueConverter-確定是否需要值轉換器,并將其應用于綁定。默認情況下,它僅檢查BooleanToVisibility轉換。
ApplyStringFormat-確定是否需要自定義字符串格式并將其應用于綁定。默認情況下,如果綁定到日期時間,則使用格式“{0:MM/dd/yyyy}”。
ApplyUpdateSourceTrigger-確定是否應將自定義更新源觸發器應用于綁定。對于WPF,始終設置為UpdateSourceTrigger=PropertyChanged。對于Silverlight,調用ApplySlverLightTriggers。
例如,讓ChangeConventionManager.Singularize使用令人敬畏的庫人性化工具。
ConventionManager.Singularize = original => original.Singularize(inputIsKnownToBePlural: false);方法
AddElementConvention–添加或替換ElementConvention。
GetElementConvention–獲取特定元素類型的約定。如果未找到,則在類型層次結構中搜索匹配項。
ApplyHeaderTemplate–將標頭模板約定應用于元素。
ApplySlverLightTriggers–對于TextBox和PasswordBox,將適當的事件連接到綁定更新,以模擬WPF的UpdateSourceTrigger=PropertyChanged。
ElementConvention
元素約定
可以通過ConventionManager.AddElementConvention添加或替換元素約定。但是,了解這些約定是什么以及在整個框架中如何使用它們是很重要的。在本文的最底部是一個代碼列表,它顯示了如何開箱即用地配置所有元素。以下是ElementConvention類的屬性和函數以及簡要說明:
Properties
ElementType–約定適用的元素類型。
ParameterProperty–使用Message.Attach聲明操作時,如果指定了引用元素的參數,但未指定該元素的屬性,則將查找ElementConvention并使用ParameterProperty。例如,如果我們有此標記:
<TextBox x:Name="something" /> <Button cal:Message.Attach="MyMethod(something)" />當按鈕的ActionMessage被創建時,我們會查找“某物”,這是一個文本框。我們得到TextBox的ElementConvention,它的ParameterProperty設置為“Text”。因此,我們從something.Text創建MyMethod的參數。
芬克斯
GetBindableProperty–獲取應在約定綁定中使用的元素的屬性。
CreateTrigger–當Message.Attach用于聲明操作,且未指定特定事件時,將查找ElementConvention并調用CreateTrigger Func來創建Interaction.Trigger。例如,在上面的Xaml中,當為按鈕創建ActionMessage時,將查找按鈕的ElementConvention并調用其CreateTrigger函數。在這種情況下,ElementConvention返回一個配置為使用Click事件的EventTrigger。
ApplyBinding–如上所述,當發生常規數據綁定時,我們正在綁定的元素將查找其ElementConvention,并調用其ApplyBinding func。默認情況下,這只傳遞給ConventionManager.SetBinding。但某些元素(見上文…或下文)對此進行了定制,以實現更強大的合成場景。
ConventionManager上有一個名為AddElementConvention的助手方法,可以這樣使用:
ConventionManager.AddElementConvention<Rating>(Rating.ValueProperty, "Value", "ValueChanged");在上述情況下,Rating.ValueProperty的第一個參數值告訴約定系統元素的默認可綁定屬性是什么。因此,如果我們在評級控件上有一個約定匹配,我們將針對ValueProperty設置綁定。第二個參數表示要在操作綁定中使用的默認屬性。因此,如果您使用指向分級控件的ElementName創建了一個操作綁定,但沒有指定屬性,那么我們將返回到“Value”屬性。最后,第三個參數表示控件的默認事件。因此,如果我們將操作附加到評級控件,但沒有指定觸發該操作的事件,則系統將退回到“ValueChanged”事件。這些元素約定允許開發人員在各種情況下提供盡可能多或盡可能少的信息,允許框架適當地填充缺少的細節。
02
—
最后
原文標題:Caliburn.Micro Xaml made easy
原文鏈接:https://caliburnmicro.com/documentation/conventions
翻譯:dotnet編程大全
C#技術群?:?添加小編微信mm1552923,備注:進群!
總結
以上是生活随笔為你收集整理的C# WPF MVVM开发框架Caliburn.Micro 关于Conventions⑧的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用 CliWrap 让C#中的命令行交
- 下一篇: 解答网友提问 | 使用VS2022快速生