在当前的开发中,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