日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > C# >内容正文

C#

C# WPF MVVM开发框架Caliburn.Micro 关于Conventions⑧

發(fā)布時(shí)間:2023/12/4 C# 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C# WPF MVVM开发框架Caliburn.Micro 关于Conventions⑧ 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

01

關(guān)于Conventions

Caliburn.Micro的一個(gè)主要特性是,它能夠通過一系列約定消除對(duì)鍋爐銘牌代碼的需求。有些人喜歡習(xí)俗,有些人討厭習(xí)俗。這就是為什么CM的約定是完全可定制的,如果不需要,甚至可以完全關(guān)閉。如果您要使用約定,并且由于它們?cè)谀J(rèn)情況下處于啟用狀態(tài),那么最好了解這些約定是什么以及它們是如何工作的。這就是本文的主題。

View Resolution (ViewModel-First)

視圖分辨率(視圖模型優(yōu)先)

基礎(chǔ)

使用CM時(shí)可能遇到的第一個(gè)約定與視圖分辨率有關(guān)。此約定影響應(yīng)用程序的任何ViewModel優(yōu)先區(qū)域。在ViewModel First中,我們有一個(gè)需要渲染到屏幕上的現(xiàn)有ViewModel。為此,CM使用一個(gè)簡(jiǎn)單的命名模式來查找UserControl1,它應(yīng)該綁定到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”變量。為了導(dǎo)出視圖,我們假設(shè)您在vm的命名中使用了文本“ViewModel”,因此我們只需通過刪除單詞“Model”將其更改為“view”。這具有更改類型名稱和名稱空間的效果。因此ViewModels.CustomerViewModel將成為Views.CustomerView。或者,如果您是按功能組織應(yīng)用程序:CustomerManagement.CustomerServiceWModel變?yōu)镃ustomerManagement.CustomerView。希望這是非常直截了當(dāng)?shù)摹+@得名稱后,我們將搜索具有該名稱的類型。我們將通過AssemblySource.Instance搜索您向CM公開的任何程序集。2如果我們找到類型,我們將創(chuàng)建一個(gè)實(shí)例(如果已注冊(cè),則從IoC容器中獲取一個(gè)實(shí)例),并將其返回給調(diào)用方。如果找不到類型,我們將生成一個(gè)帶有適當(dāng)“not found”消息的視圖。

現(xiàn)在,回到“上下文”值。這就是CM如何支持同一ViewModel上的多個(gè)視圖。如果提供了上下文(通常是字符串或枚舉),我們將根據(jù)該值對(duì)名稱進(jìn)行進(jìn)一步轉(zhuǎn)換。通過從末尾刪除單詞“View”并附加上下文,此轉(zhuǎn)換有效地假設(shè)您擁有用于不同視圖的文件夾(命名空間)。因此,給定“Master”上下文,我們的ViewModels.CustomerViewModel將變成Views.Customer.Master。

其他需要知道的事情

除了實(shí)例化視圖外,GetOrCreateViewType還將在視圖上調(diào)用InitializeComponent(如果存在)。這意味著,對(duì)于由ViewLocator創(chuàng)建的視圖,根本不需要代碼落后。如果這讓您感到高興,您可以刪除它們:)您還應(yīng)該知道ViewLocator.LocateForModelType從不直接調(diào)用。它總是通過ViewLocator.LocateForModel間接調(diào)用。LocateForModel獲取ViewModel的實(shí)例并返回視圖的實(shí)例。LocateForModel的功能之一是檢查ViewModel是否實(shí)現(xiàn)了IViewAware。如果是這樣,它將調(diào)用它的GetView方法來查看您是否有緩存的視圖,或者是否顯式地處理視圖創(chuàng)建。如果不是,則將ViewModel的類型傳遞給LocateForModelType。

定制

開箱即用的約定非常簡(jiǎn)單,它基于我們?cè)诂F(xiàn)實(shí)世界中使用過和看到其他人使用過的許多模式。然而,您絕不局限于這些簡(jiǎn)單的模式。您會(huì)注意到上面討論的所有方法都是作為Funcs實(shí)現(xiàn)的,而不是實(shí)際的方法。這意味著您可以通過簡(jiǎn)單地用自己的實(shí)現(xiàn)替換它們來定制它們。如果只想添加到現(xiàn)有行為,只需將現(xiàn)有Func存儲(chǔ)在變量中,創(chuàng)建一個(gè)調(diào)用舊函數(shù)的新Func,然后將新Func分配給ViewLocator.LocateForModelType。

v1.1的更改v1.1中我們完全更改了LocateForModelType函數(shù)的實(shí)現(xiàn)。現(xiàn)在,我們使用新的NameTransformer類的一個(gè)實(shí)例以及預(yù)先配置的基于RexEx的規(guī)則來進(jìn)行名稱映射。我們支持與以前相同的現(xiàn)成約定,但現(xiàn)在您可以更輕松地添加自定義轉(zhuǎn)換規(guī)則。

框架使用

框架使用ViewLocator的地方有三個(gè);您可以期望應(yīng)用視圖位置約定的三個(gè)位置。第一名是Bootstrapper。在這里,您的根ViewModel被傳遞給定位器,以確定應(yīng)用程序的shell應(yīng)該如何呈現(xiàn)。在Silverlight中,這將導(dǎo)致設(shè)置或您的RootVisual。在WPF中,這將創(chuàng)建主窗口。事實(shí)上,在WPF中,引導(dǎo)程序?qū)⒋宋薪oWindowManager,這使我想到……ViewLocator使用的第二個(gè)位置是WindowManager,它調(diào)用它來確定任何對(duì)話框ViewModels應(yīng)如何呈現(xiàn)。利用這些約定的第三個(gè)也是最后一個(gè)地方是View.Model attached屬性。每當(dāng)您使用UIElement上的View.Model attached屬性進(jìn)行ViewModel首次合成渲染時(shí),都會(huì)調(diào)用定位器以查看合成的ViewModel應(yīng)如何在UI中的該位置進(jìn)行渲染。您可以在UI中顯式使用View.Model attached屬性(可以選擇將其與View.Context attached屬性組合以進(jìn)行上下文呈現(xiàn)),也可以按約定添加該屬性,從而實(shí)現(xiàn)視圖的常規(guī)組合。請(qǐng)參閱下面關(guān)于屬性綁定約定的部分。

ViewModel Resolution (View-First)

視圖模型分辨率(視圖優(yōu)先)

基礎(chǔ)

盡管Caliburn.Micro更喜歡ViewModel-First開發(fā),但有時(shí)您可能希望采用視圖優(yōu)先的方法,尤其是在使用WP7時(shí)。如果從視圖開始,則可能需要解析ViewModel。我們?cè)谶@個(gè)場(chǎng)景中使用了與視圖位置類似的命名約定。這由ViewModelLocator.LocateForViewType處理。當(dāng)使用視圖位置時(shí),我們將“ViewModel”的實(shí)例更改為“View”,而使用ViewModel位置時(shí),我們將“View”更改為“ViewModel”。另一個(gè)有趣的區(qū)別在于我們?nèi)绾潍@得ViewModel本身的實(shí)例。由于ViewModels可能由接口或具體類注冊(cè),因此我們也嘗試生成可能的接口名稱。如果我們找到匹配項(xiàng),我們將從IoC容器中解析它。

其他需要知道的事情

實(shí)際上,框架從未直接調(diào)用ViewModelLocator.LocateForViewType。它由ViewModelLocator.LocateForView在內(nèi)部調(diào)用。LocateForView首先檢查視圖實(shí)例的DataContext,查看您以前是否緩存或自定義創(chuàng)建了ViewModel。如果DataContext為null,則只有在該情況下才會(huì)調(diào)用LocateForViewType。最后要注意的是,自動(dòng)初始化組件調(diào)用在性質(zhì)上不受view first支持。

定制

在v1.1中,我們完全改變了LocateForViewType函數(shù)的實(shí)現(xiàn)。現(xiàn)在,我們使用新的NameTransformer類的一個(gè)實(shí)例以及預(yù)先配置的基于RexEx的規(guī)則來進(jìn)行名稱映射。我們支持與以前相同的現(xiàn)成約定,但現(xiàn)在您可以更輕松地添加自定義轉(zhuǎn)換規(guī)則。

框架使用

ViewModelLocator僅由框架的WP7版本使用。FrameAdapter使用它,它確保每次導(dǎo)航到頁面時(shí),都提供了正確的ViewModel。如果需要的話,它可以很容易地適應(yīng)Silverlight導(dǎo)航框架的使用。

ViewModelBinder

基礎(chǔ)

當(dāng)我們將視圖和ViewModel綁定在一起時(shí),無論是使用ViewModel優(yōu)先還是視圖優(yōu)先方法,都會(huì)調(diào)用ViewModelBinder.bind方法。此方法將視圖的Action.Target設(shè)置為ViewModel,并相應(yīng)地將DataContext設(shè)置為相同的值。4它還檢查ViewModel是否實(shí)現(xiàn)了IViewAware,如果實(shí)現(xiàn)了,則將視圖傳遞給ViewModel。如果更適合您的場(chǎng)景,這將允許更具監(jiān)督性的控制器樣式設(shè)計(jì)。ViewModelBinder所做的最后一件重要事情是確定是否需要?jiǎng)?chuàng)建任何常規(guī)屬性綁定或操作。為此,它在UI中搜索綁定/操作的候選元素列表,并將其與ViewModel的屬性和方法進(jìn)行比較。當(dāng)找到匹配項(xiàng)時(shí),它將代表您創(chuàng)建綁定或操作。

其他需要知道的事情

在所有平臺(tái)上,約定都不能應(yīng)用于DataTemplate的內(nèi)容。這是Xaml模板系統(tǒng)的當(dāng)前限制。我已經(jīng)要求微軟解決這個(gè)問題,但我懷疑他們是否會(huì)回應(yīng)。因此,為了將綁定和操作約定應(yīng)用于DataTemplate,必須將Bind.Model=“{Binding}”附加屬性添加到DataTemplate內(nèi)的根元素。這為Caliburn.Micro提供了必要的鉤子,以便在每次從DataTemplate實(shí)例化UI時(shí)應(yīng)用其約定。

在WP7平臺(tái)上,如果要綁定的視圖是PhoneApplicationPage,則此服務(wù)負(fù)責(zé)將操作連接到ApplicationBar的按鈕和菜單。有關(guān)這方面的更多信息,請(qǐng)參閱WP7特定文檔。

定制

如果您決定不喜歡ViewModelBinder的行為(更多細(xì)節(jié)見下文),它將遵循與上述框架服務(wù)相同的模式。它有幾個(gè)函數(shù),您可以用自己的實(shí)現(xiàn)來替換,例如Bind、BindActions和BindProperties。不過,定制最重要的方面可能是能夠關(guān)閉活頁夾的約定功能。為此,請(qǐng)將ViewModelBinder.ApplyConventionsByDefault設(shè)置為false。如果要逐個(gè)視圖啟用它,可以在視圖中將view.ApplyConventions attached屬性設(shè)置為true。此附加屬性以兩種方式工作。因此,如果默認(rèn)情況下啟用了約定,但需要逐個(gè)視圖將其禁用,則只需將此屬性設(shè)置為false。

框架使用

ViewModelBinder用于Caliburn.Micro內(nèi)部的三個(gè)位置。第一個(gè)位置是View.Model附加屬性的實(shí)現(xiàn)內(nèi)部。此屬性獲取您的ViewModel,使用ViewLocator定位視圖,然后將它們一起傳遞到ViewModelBinder。綁定完成后,視圖被注入到定義屬性的元素中。這是ViewModel的第一個(gè)使用模式。使用ViewModelBinder的第二個(gè)位置是Bind.Model attached屬性的實(shí)現(xiàn)內(nèi)部。此屬性獲取ViewModel并將其與定義該屬性的元素一起傳遞到ViewModelBinder。換言之,這是視圖優(yōu)先,因?yàn)槟呀?jīng)在Xaml中內(nèi)聯(lián)實(shí)例化了視圖,然后只是針對(duì)ViewModel調(diào)用綁定。使用ViewModelBinder的最后一個(gè)位置是框架的WP7版本。在FrameAdapter內(nèi)部,當(dāng)頁面被導(dǎo)航到時(shí),首先使用ViewModelLocator獲取該頁面的ViewModel。然后,使用ViewModelBinder將ViewModel連接到頁面。

Element Location

基礎(chǔ)

現(xiàn)在,您已經(jīng)了解了ViewModelBinder的基本角色以及框架使用它的位置,我想深入了解它如何應(yīng)用約定的細(xì)節(jié)。如上所述,ViewModelBinder“在UI中搜索綁定/操作的候選元素列表,并將其與ViewModel的屬性和方法進(jìn)行比較。”了解其工作原理的第一步是了解框架如何確定UI中哪些元素可能是約定的候選元素。它通過在名為GetNamedElementsInScope的靜態(tài)ExtensionMethods類上使用func來實(shí)現(xiàn)這一點(diǎn)。5基本上,該方法有兩個(gè)功能。首先,它確定了要在其中搜索元素的范圍。這意味著它將遍歷樹,直到找到合適的根節(jié)點(diǎn),例如窗口、UserControl或沒有父節(jié)點(diǎn)的元素(表示我們?cè)贒ataTemplate中)。一旦定義了作用域的“外部”邊界,它就開始了第二項(xiàng)任務(wù):定位該作用域中具有名稱的所有元素。搜索會(huì)小心地遵守“內(nèi)部”范圍邊界,不遍歷子用戶控件的內(nèi)部。然后,ViewModelBinder使用此函數(shù)返回的元素應(yīng)用約定。

其他需要知道的事情

GetNamedElementsInScope方法可以完成一些開箱即用的限制。它只能搜索可視化樹ContentControl.Content和ItemsControl.Items。在WPF中,它還搜索HeaderContentControl.Header和HeaderEditsControl.Header。這意味著,當(dāng)嘗試應(yīng)用約定時(shí),將找不到上下文菜單、工具提示或任何其他不在可視化樹中或這些特殊位置之一的內(nèi)容。

定制

您可能不會(huì)遇到與上述元素位置限制相關(guān)的問題。但是如果您這樣做了,您可以輕松地用自己的實(shí)現(xiàn)替換默認(rèn)實(shí)現(xiàn)。您可能會(huì)選擇使用以下一種有趣的技術(shù):如果視圖是用戶控件或窗口,則不必遍歷元素樹,而是使用一些反射來發(fā)現(xiàn)從FrameworkElement繼承的所有私有字段。我們知道,在編譯Xaml文件時(shí),會(huì)為所有具有x:Name的文件創(chuàng)建一個(gè)私有字段。利用這個(gè)優(yōu)勢(shì)。不過,您必須回到DataTemplateUI的現(xiàn)有實(shí)現(xiàn)。我不提供這種開箱即用的實(shí)現(xiàn),因?yàn)樗荒鼙WC在Silverlight中成功。原因是Silverlight不允許您獲取私有字段的值,除非調(diào)用代碼是定義字段的代碼。但是,如果所有視圖都是在單個(gè)程序集中定義的,那么可以通過在與視圖相同的程序集中創(chuàng)建新實(shí)現(xiàn)來輕松地進(jìn)行我剛才描述的修改。此外,如果您有一個(gè)多程序集項(xiàng)目,您可以編寫一點(diǎn)管道代碼,讓GetNamedElementsInScope funct找到可以實(shí)際執(zhí)行反射的特定于程序集的實(shí)現(xiàn)。

框架使用

我已經(jīng)提到,當(dāng)ViewModelBinder嘗試按約定綁定屬性或方法時(shí),會(huì)出現(xiàn)元素位置。但是,還有第二個(gè)地方使用此功能:解析器。每當(dāng)您使用Message.Attach并且您的操作包含參數(shù)時(shí),消息解析器必須找到您用作參數(shù)輸入的元素。看起來我們可以只做一個(gè)簡(jiǎn)單的FindName,但是FindName是區(qū)分大小寫的。因此,我們必須使用自定義實(shí)現(xiàn),它執(zhí)行不區(qū)分大小寫的搜索。這確保了在兩個(gè)地方使用相同的綁定語義。

Action Matching

基礎(chǔ)

在找到約定綁定的元素后,ViewModelBinder要做的下一件事是檢查它們是否與ViewModel上的方法匹配。它通過使用一些反射來獲得ViewModel的公共方法來實(shí)現(xiàn)這一點(diǎn)。然后它在它們上面循環(huán),尋找與元素匹配的不區(qū)分大小寫的名稱。如果找到匹配項(xiàng),并且元素上沒有任何預(yù)先存在的Interaction.Triggers,則會(huì)附加一個(gè)操作。檢查預(yù)先存在的觸發(fā)器用于防止約定系統(tǒng)創(chuàng)建與開發(fā)人員在標(biāo)記中明確聲明的操作重復(fù)的操作。為了安全起見,如果您在匹配的元素上聲明了任何觸發(fā)器,那么將跳過它。

其他需要知道的事情

常規(guī)操作是通過在元素上設(shè)置Message.Attach attached屬性創(chuàng)建的。讓我們看看這是如何建立起來的:

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);

如您所見,我們構(gòu)建了一個(gè)表示消息的字符串。此字符串僅包含消息的操作部分;未聲明任何事件。您還可以看到,它循環(huán)遍歷方法的參數(shù),以便將它們包含在操作中。如果參數(shù)名與一個(gè)特殊的參數(shù)值相同,我們確保將“$”附加到它,以便解析器能夠正確識(shí)別它,之后調(diào)用操作時(shí)MessageBinder能夠正確識(shí)別它。

設(shè)置Message.Attach屬性后,解析器立即啟動(dòng),將字符串消息轉(zhuǎn)換為某種類型的TriggerBase,其中包含關(guān)聯(lián)的ActionMessage。因?yàn)槲覀儧]有將事件聲明為消息的一部分,所以解析器會(huì)查找消息所附加到的元素類型的默認(rèn)觸發(fā)器。例如,如果消息被附加到一個(gè)按鈕,那么我們將得到一個(gè)EventTrigger,其事件設(shè)置為Click。此信息通過ConventionManager配置,具有合理的現(xiàn)成默認(rèn)值。請(qǐng)參閱下面有關(guān)ConventionManager和ElementConventions的部分以了解更多信息。ElementConvention用于創(chuàng)建觸發(fā)器,然后解析器將操作信息轉(zhuǎn)換為ActionMessage。這兩個(gè)元素連接在一起,然后添加到Interaction.Triggers元素的集合中。

定制

ViewModelBinder.BindActions是一個(gè)Func,因此如果需要,可以完全替換。通過ConventionManager添加或更改ElementConventions也會(huì)影響操作的組合方式。下面將詳細(xì)介紹。

框架使用

BindActions僅由ViewModelBinder使用。

Property Matching

基礎(chǔ)

一旦動(dòng)作綁定完成,我們就轉(zhuǎn)到屬性綁定。它遵循類似的過程,在命名元素中循環(huán),并在屬性上查找不區(qū)分大小寫的名稱匹配項(xiàng)。一旦找到匹配項(xiàng),我們就可以從ConventionManager獲取ElementConventions,這樣我們就可以確定該元素上的數(shù)據(jù)綁定方式。ElementConvention定義了一個(gè)ApplyBinding Func,它接受視圖模型類型、屬性路徑、屬性信息、元素實(shí)例和約定本身。此Func負(fù)責(zé)使用提供的所有上下文信息在元素上創(chuàng)建綁定。最妙的是,如果需要,我們可以為每個(gè)元素定制綁定行為。CM為ConventionManager上的大多數(shù)元素定義了ApplyBinding的基本實(shí)現(xiàn)。這叫做挫折,看起來像這樣:

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;};

此方法所做的第一件事是通過調(diào)用ElementConvention上的GetBindableProperty來獲取應(yīng)該綁定的依賴項(xiàng)屬性。接下來,我們檢查該屬性是否已經(jīng)存在綁定集。如果有,我們不想覆蓋它。開發(fā)人員可能在這里做了一些特殊的事情,因此我們返回false,表示尚未添加綁定。假設(shè)不存在綁定,該方法基本上會(huì)委托ConventionManager上的其他方法來獲取綁定應(yīng)用程序的詳細(xì)信息。希望這一部分有意義。一旦綁定被完全構(gòu)造,我們將其添加到元素中,并返回true,指示應(yīng)用了約定。

屬性匹配還有另一個(gè)重要方面,我還沒有提到。我們也可以通過約定在深層屬性路徑上進(jìn)行匹配。因此,假設(shè)您的ViewModel上有一個(gè)Customer屬性,它有一個(gè)FirstName屬性,您希望將文本框綁定到該屬性。只需給文本框一個(gè)x:Name“Customer_FirstName”,ViewModelBinder將完成所有工作以確保該屬性有效,并將正確的視圖模型類型、屬性信息和屬性路徑傳遞給ElementConvention的ApplyBinding函數(shù)。

其他需要知道的事情

我在上面提到,“CM為大多數(shù)元素定義了ApplyBinding的基本實(shí)現(xiàn)。”它還為通常與特定使用模式或組合關(guān)聯(lián)的元素定義了ApplyBinding Func的幾個(gè)自定義實(shí)現(xiàn)。對(duì)于WPF和Silverlight,ItemsControl和Selector具有自定義綁定行為。除了在ItemsControl上綁定ItemsSource外,ApplyBinding函數(shù)還檢查ItemTemplate、DisplayMemberPath和ItemTemplateSelector(WPF)屬性。如果這些都沒有設(shè)置,那么框架就會(huì)知道,由于您沒有為項(xiàng)目指定呈現(xiàn)器,它應(yīng)該按常規(guī)添加一個(gè)。7因此,我們將ItemTemplate設(shè)置為默認(rèn)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>

由于此模板創(chuàng)建了一個(gè)帶有View.Model附加屬性的ContentControl,因此我們?yōu)镮temsControl創(chuàng)建了豐富組合的可能性。因此,無論項(xiàng)目是什么,View.Model attached屬性都允許我們調(diào)用ViewModel First工作流:找到項(xiàng)目的視圖,將項(xiàng)目和視圖傳遞給ViewModelBinder(ViewModelBinder反過來設(shè)置自己的約定,可能會(huì)調(diào)用更多組合),然后獲取視圖并將其注入ContentControl。選擇器的行為與ItemsControl相同,但在SelectedItem屬性周圍有一個(gè)附加約定。假設(shè)您的選擇器稱為Items。我們首先遵循上述約定,將ItemsSource綁定到Items,并檢測(cè)是否需要添加默認(rèn)的DataTemplate。然后,檢查SelectedItem屬性是否已綁定。如果沒有,我們將在ViewModel上查找可以綁定到SelectedItem的三個(gè)候選屬性:ActiveItem、SelectedItem和CurrentItem。如果找到其中一個(gè),我們將添加綁定。因此,這里的模式是,我們首先調(diào)用ConventionManager.Singularize來指定集合屬性的名稱。在這種情況下,“Items”變?yōu)椤癐tem”,然后我們稱ConventionManager.DerivePotentialSelectionNames,它在“Active”、“Selected”和“Current”前面加上“Active”和“Current”以使上述三個(gè)候選項(xiàng)成為“Item”。然后,如果在ViewModel上找到其中一個(gè),我們將創(chuàng)建一個(gè)綁定。對(duì)于WPF,我們?yōu)門abControl提供了一個(gè)特殊的ApplyBinding行為。8它采用選擇器的所有約定(將其ContentTemplate而不是ItemTemplate設(shè)置為DefaultDataTemplate),并為選項(xiàng)卡標(biāo)題的內(nèi)容提供了一個(gè)附加約定。如果未設(shè)置TabControl的DisplayMemberPath,并且ViewModel實(shí)現(xiàn)IHaveDisplayName,則我們將其ItemTemplate設(shè)置為DefaultHeaderTemplate,如下所示:

<DataTemplate xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"><TextBlock Text="{Binding DisplayName, Mode=TwoWay}" /> </DataTemplate>

因此,對(duì)于命名的WPF TabControl,我們可以常規(guī)地在選項(xiàng)卡列表(ItemsSource)中綁定選項(xiàng)卡項(xiàng)的名稱(ItemTemplate)、每個(gè)選項(xiàng)卡的內(nèi)容(ContentTemplate),并保持所選選項(xiàng)卡與模型同步(SelectedItem)。對(duì)于這樣一行Xaml來說,這還不錯(cuò):

<TabControl x:Name="Items" />

除了上面列出的特殊情況外,我們還有一個(gè)很重要的問題:ContentControl。在本例中,我們不提供自定義ApplyBinding函數(shù),但提供自定義GetBindableProperty函數(shù)。對(duì)于ContentControl,當(dāng)我們決定綁定到哪個(gè)屬性時(shí),我們檢查ContentTemplate和ContentTemplateSelector(WPF)。如果它們都為null,則表示尚未為模型指定渲染器。因此,我們假設(shè)您希望使用ViewModel First工作流。我們通過讓GetBindableProperty函數(shù)返回View.Model attached屬性作為要綁定的屬性來實(shí)現(xiàn)這一點(diǎn)。在所有其他情況下,ContentControl將綁定到Content屬性。通過在沒有ContentTemplate的情況下選擇View.Model屬性,我們可以實(shí)現(xiàn)豐富的合成。

我希望當(dāng)你思考這些特殊情況時(shí),你會(huì)發(fā)現(xiàn)它們是有道理的。一如既往,如果你不喜歡它們,你可以改變它們…

定制

正如您所想象的,通過替換ViewModelBinder上的Func,BindProperties功能完全可以自定義。例如,如果你喜歡動(dòng)作約定而不是屬性約定,你可以用一個(gè)不做任何事情的Func替換這個(gè)Func。然而,您可能需要更細(xì)粒度的控制。幸運(yùn)的是,ConventionManager或特定ElementConvention的幾乎每個(gè)方面都是可定制的。有關(guān)ConventionManager的更多詳細(xì)信息如下。

配置約定的常用方法之一是向系統(tǒng)中添加新約定。最常見的情況是添加Silverlight toolkit控件或WP7 toolkit控件。下面是一個(gè)示例,說明如何為WP7 Pivot控件設(shè)置一個(gè)高級(jí)約定,使其與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使用。

會(huì)議經(jīng)理

如果您已經(jīng)閱讀了本文,您就會(huì)知道ConventionManager在很大程度上受到操作和屬性綁定機(jī)制的影響。它是微調(diào)框架中大多數(shù)約定行為的網(wǎng)關(guān)。以下是可用于自定義框架約定的可替換函數(shù)和屬性的列表:

性質(zhì)

BooleantVisibilityConverter–用于將布爾值轉(zhuǎn)換為可見性并返回的默認(rèn)IValueConverter。由ApplyValueConverter使用。

IncludeStaticProperties-指示在約定名稱匹配期間是否應(yīng)包括靜態(tài)屬性。默認(rèn)情況下為False。

DefaultItemTemplate–當(dāng)ItemsControl或ContentControl需要DataTemplate時(shí)使用。

DefaultHeaderTemplate–當(dāng)TabControl需要標(biāo)題模板時(shí),由ApplyHeaderTemplate使用。

芬克斯

單數(shù)化–將單詞從復(fù)數(shù)形式轉(zhuǎn)換為單數(shù)形式。默認(rèn)的實(shí)現(xiàn)是非常基本的,只是去掉了后面的's'。

DerivePotentialSelectionNames–給定基本集合名稱,返回表示所選內(nèi)容的可能屬性名稱列表。使用Singularize。

SetBinding–ElementConventions使用的ApplyBinding的默認(rèn)實(shí)現(xiàn)(更多信息見下文)。更改此選項(xiàng)將更改所有常規(guī)綁定的應(yīng)用方式。在內(nèi)部使用以下函數(shù):

HasBinding—確定特定依賴項(xiàng)屬性是否已在提供的元素上具有綁定。如果綁定已存在,則SetBinding將中止。

ApplyBindingMode-將適當(dāng)?shù)慕壎J綉?yīng)用于綁定。

ApplyValidation—確定是否以及在綁定上啟用何種類型的驗(yàn)證。

ApplyValueConverter-確定是否需要值轉(zhuǎn)換器,并將其應(yīng)用于綁定。默認(rèn)情況下,它僅檢查BooleanToVisibility轉(zhuǎn)換。

ApplyStringFormat-確定是否需要自定義字符串格式并將其應(yīng)用于綁定。默認(rèn)情況下,如果綁定到日期時(shí)間,則使用格式“{0:MM/dd/yyyy}”。

ApplyUpdateSourceTrigger-確定是否應(yīng)將自定義更新源觸發(fā)器應(yīng)用于綁定。對(duì)于WPF,始終設(shè)置為UpdateSourceTrigger=PropertyChanged。對(duì)于Silverlight,調(diào)用ApplySlverLightTriggers。

例如,讓ChangeConventionManager.Singularize使用令人敬畏的庫人性化工具。

ConventionManager.Singularize = original => original.Singularize(inputIsKnownToBePlural: false);

方法

AddElementConvention–添加或替換ElementConvention。

GetElementConvention–獲取特定元素類型的約定。如果未找到,則在類型層次結(jié)構(gòu)中搜索匹配項(xiàng)。

ApplyHeaderTemplate–將標(biāo)頭模板約定應(yīng)用于元素。

ApplySlverLightTriggers–對(duì)于TextBox和PasswordBox,將適當(dāng)?shù)氖录B接到綁定更新,以模擬WPF的UpdateSourceTrigger=PropertyChanged。

ElementConvention

元素約定

可以通過ConventionManager.AddElementConvention添加或替換元素約定。但是,了解這些約定是什么以及在整個(gè)框架中如何使用它們是很重要的。在本文的最底部是一個(gè)代碼列表,它顯示了如何開箱即用地配置所有元素。以下是ElementConvention類的屬性和函數(shù)以及簡(jiǎn)要說明:

Properties

ElementType–約定適用的元素類型。

ParameterProperty–使用Message.Attach聲明操作時(shí),如果指定了引用元素的參數(shù),但未指定該元素的屬性,則將查找ElementConvention并使用ParameterProperty。例如,如果我們有此標(biāo)記:

<TextBox x:Name="something" /> <Button cal:Message.Attach="MyMethod(something)" />

當(dāng)按鈕的ActionMessage被創(chuàng)建時(shí),我們會(huì)查找“某物”,這是一個(gè)文本框。我們得到TextBox的ElementConvention,它的ParameterProperty設(shè)置為“Text”。因此,我們從something.Text創(chuàng)建MyMethod的參數(shù)。

芬克斯

GetBindableProperty–獲取應(yīng)在約定綁定中使用的元素的屬性。

CreateTrigger–當(dāng)Message.Attach用于聲明操作,且未指定特定事件時(shí),將查找ElementConvention并調(diào)用CreateTrigger Func來創(chuàng)建Interaction.Trigger。例如,在上面的Xaml中,當(dāng)為按鈕創(chuàng)建ActionMessage時(shí),將查找按鈕的ElementConvention并調(diào)用其CreateTrigger函數(shù)。在這種情況下,ElementConvention返回一個(gè)配置為使用Click事件的EventTrigger。

ApplyBinding–如上所述,當(dāng)發(fā)生常規(guī)數(shù)據(jù)綁定時(shí),我們正在綁定的元素將查找其ElementConvention,并調(diào)用其ApplyBinding func。默認(rèn)情況下,這只傳遞給ConventionManager.SetBinding。但某些元素(見上文…或下文)對(duì)此進(jìn)行了定制,以實(shí)現(xiàn)更強(qiáng)大的合成場(chǎng)景。

ConventionManager上有一個(gè)名為AddElementConvention的助手方法,可以這樣使用:

ConventionManager.AddElementConvention<Rating>(Rating.ValueProperty, "Value", "ValueChanged");

在上述情況下,Rating.ValueProperty的第一個(gè)參數(shù)值告訴約定系統(tǒng)元素的默認(rèn)可綁定屬性是什么。因此,如果我們?cè)谠u(píng)級(jí)控件上有一個(gè)約定匹配,我們將針對(duì)ValueProperty設(shè)置綁定。第二個(gè)參數(shù)表示要在操作綁定中使用的默認(rèn)屬性。因此,如果您使用指向分級(jí)控件的ElementName創(chuàng)建了一個(gè)操作綁定,但沒有指定屬性,那么我們將返回到“Value”屬性。最后,第三個(gè)參數(shù)表示控件的默認(rèn)事件。因此,如果我們將操作附加到評(píng)級(jí)控件,但沒有指定觸發(fā)該操作的事件,則系統(tǒng)將退回到“ValueChanged”事件。這些元素約定允許開發(fā)人員在各種情況下提供盡可能多或盡可能少的信息,允許框架適當(dāng)?shù)靥畛淙鄙俚募?xì)節(jié)。

02

最后

原文標(biāo)題:Caliburn.Micro Xaml made easy

原文鏈接:https://caliburnmicro.com/documentation/conventions

翻譯:dotnet編程大全

C#技術(shù)群?:?添加小編微信mm1552923,備注:進(jìn)群!

總結(jié)

以上是生活随笔為你收集整理的C# WPF MVVM开发框架Caliburn.Micro 关于Conventions⑧的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。