在當前的開發中,NuGet的使用已經有了不小的地位,特別是應用.NET Core的UWP開發裏,模塊化的平臺自己更是直接依賴於NuGet這一包管理器。html
有時本身開發了一個不錯的控組件,想經過NuGet與廣大開發中分享,以享受包管理器快捷、模塊化的優點,該如何作呢?本文將就基本的UWP控件的開發與打包,來爲你們介紹UWP與NuGet配合的過程。windows
對於控件的開發,想必你們都是身經百戰,已無須多言。不過本文仍有一些小小的建議,能夠幫助你們創造出更普適、更易用的控件。架構
對於UWP應用來講,portable類庫、普通的UWP class類庫以及Windows Runtime組件庫,都是能夠接受的,可是這裏推薦你們使用Windows Runtime組件來組織本身的控件。得益於WinRT的新架構,只要聽從了WinRT的接口要求(若是違反了,編譯器會報告的),組件就能在C# app或者C++/CX app裏交互使用了,好處不小。app
另外,就不得不提到一些爲了能讓控件更易使用所需的準備。以前咱們開發了PullToRefresh.UWP這一控件,而且經過NuGet包的形式放出。後來咱們慢慢地注意到這一控件會使得Visual Studio中的XAML設計器沒法正常工做,爲此咱們進行了一些探索,得出的經驗就是:對於新編寫的控件,須要考慮到XAML框架的佈局問題。框架
XAML控件框架,由Measure和Arrange兩個步驟貫穿始終,諸如SizeChanged等事件都是這兩個步驟的產物。而VS的XAML設計器在分析開發者編寫的XAML文件時,也是着重考慮這兩個標準的佈局流程的。至於Loaded,SizeChanged等等事件,若是控件編寫者把佈局操做置於其中(雖然方便,但實際上還會引起新一輪佈局,可能影響性能),並且設計器有時會考慮不到,致使設計器表現異常(控件外觀改變,甚至設計器崩潰)。模塊化
XAML的標準控件自沒必要說,設計器能夠很好的解析它們的XAML佈局(在generic.xaml中)以及它們提供的Measure和Arrange過程。這也是你們能在XAML設計器中看到Grid按咱們的定義分割行列,StackPanel自動以棧式排布子項的緣由。若是你們的新編寫的控件着重於業務,好比完成必定的計算後更新文本顯示,也無需擔憂這些。可是,若是控件更傾向於提供某種佈局方案,就不能不考慮這一點了。因此考慮到有時部分實現會致使引用控件後,設計器工做不正常,編寫控件時應儘可能使用Measure/Arrange來編寫複雜佈局過程,而不是依賴佈局事件。(固然簡單的實現徹底能夠在事件中實現)工具
此外還有一個小技巧,就是Windows.ApplicationModel.DesignMode類[1]的DesignModeEnabled屬性。顧名思義,它就是用來判斷此時控件是工做在實際的應用裏,仍是VS的設計器裏的。有時控件的佈局實在是很是複雜,哎呀設計器總不正常搞不定,不妨對這一屬性進行一下判斷,爲設計器提供簡化的佈局流程。佈局
通常狀況下,一個metro控件會帶上零零散散一堆文件,XAML佈局啊code-behind啊,控件還分自定義和模板的……性能
爲了讓NuGet包能在引用者的項目里正常工做,須要按正確的結構組織編譯出的種種控件文件。爲了方便這一過程,Visual Studio提供了一個選項,在控件項目的屬性——生成(Build)頁中,勾選「Generate Library Layout」,如圖:網站
這以後再build,就會在輸出目錄裏組織出正確的包結構了。(固然須要在release也進行這一配置)
另外,須要特別注意的一點,就是*.rd.xml文件[2]。有時項目中會存在這一文件(在根目錄\Properties文件夾下),而且在引用者項目處於release配置下,須要調用本地.NET native工具鏈時,可能會須要這一文件。若是不把它也放進包中,有時會致使引用者項目編譯失敗。這一文件須要特別處理,咱們用NuGet打包章節再說。
打包的第一步就是獲取NuGet程序:https://www.nuget.org/
同時,須要一個配置文件來講明當前的包信息,即nuspec配置文件。接下來本文用PullToRefresh.UWP這一控件包來舉例,此例中配置文件命名爲PullToRefresh.UWP.nuspec。其最基本的格式以下:
<?xml version="1.0"?> <package > <metadata> <id>PullToRefresh.UWP</id> <version>0.3.4</version> <title>PullToRefresh.UWP</title> <authors>MS-UAP</authors> <owners>MS-UAP</owners> <projectUrl>http://www.cnblogs.com/ms-uap/p/4814507.html</projectUrl> <requireLicenseAcceptance>false</requireLicenseAcceptance> <description>Generic Pull Down to Refresh implementation for UWP.</description> <copyright>Copyright 2015</copyright> <tags>UWP XAML</tags> </metadata> </package>
固然還有別的辦法建立這個文件,好比從程序集建立、直接和項目關聯等等。這裏咱們採用最簡單的方法,其餘方法能夠參見NuGet的幫助文檔[3]。
而後咱們須要在nuspec所在的文件夾裏創建一些目錄,用來表示NuGet包支持的平臺:
.\lib\uap10.0 就表示UWP平臺了。
而後把最初VS生成的文件拷貝到.\lib\uap10.0裏。
對*.rd.xml的特別處理:
首先須要在build出的項目名文件夾(.\lib\uap10.0\PullToRefresh.UWP)裏創建一個Properties文件夾,並把rd.xml文件放到那裏(若是有這個文件的話)。
所有完成後,待打包的文件 總的結構以下:
│ PullToRefresh.UWP.nuspec │ └─lib └─uap10.0 │ PullToRefresh.UWP.pri │ PullToRefresh.UWP.winmd │ └─PullToRefresh.UWP │ PullToRefresh.UWP.xr.xml │ ├─Properties │ PullToRefresh.UWP.rd.xml (須要額外處理) │ └─Themes Generic.xbf
最後在nuspec所在的文件夾裏,用命令行執行「nuget pack PullToRefresh.UWP.nuspec「,就會在當前目錄生成一個NuGet包了!而後就能夠在NuGet的網站上將其上傳了。
在此例中,咱們只創建了一個lib文件夾。實際上,NuGet還在標準中支持build、ref、runtimes等目錄,在這裏爲你們作一些簡單介紹,爲不一樣的應用場景起到一些啓發:
更多信息仍是須要參見NuGet目錄結構說明[4]。
P.S. 由於native的dll必須被拷貝到運行文件目錄裏去,除了經過runtimes目錄自動完成複製,還能經過在build目錄裏添加MSBuild配置文件,好比經過這樣的方式告訴編譯器 平臺相關的文件在哪:
<Target Name="xxx" BeforeTargets="ResolveAssemblyReferences"> <ItemGroup Condition=" '$(Platform)' == 'x86' or '$(Platform)' == 'x64' or '$(Platform)' == 'ARM'"> <Reference> <HintPath>包含$(Platform)的路徑</HintPath> </Reference> </ItemGroup> </Target>
對於一般用C#編寫的庫,由於是託管代碼,咱們能夠直接將其配置爲生成AnyCPU類型的程序集或WinRT組件,並將編譯出的文件直接置於lib\uap10.0\下。咱們的PullToRefresh.UWP例子就是如此。
[1] DesignMode類:https://msdn.microsoft.com/library/windows/apps/br224664
[2] Runtime Directives (rd.xml) 配置文件:https://msdn.microsoft.com/en-us/library/dn600639(v=vs.110).aspx
[3] NuGet建立包:http://docs.nuget.org/Create/Creating-and-Publishing-a-Package
[4] NuGet目錄結構說明:http://docs.nuget.org/create/uwp-create#directory-structure