某些标记扩展会引发编译错误。例如,如果找不到所引用的类,则StaticExtension(x:Static)会引发编译错误。有人知道这是什么机制吗?它是内置在XAML编译器中还是可用于自定义标记扩展的功能?
编辑:下面的mfeingold建议我查看IVsErrorList接口,但我无法立即看出如何帮助编写生成编译时错误的标记扩展。有示例吗?
扩展BAML编译过程以记录额外的错误
去年我遇到了同样的问题。我正在编写自己的扩展程序,希望在特定情况下进行编译时错误检查,但是发现仅从ProvideValue
中抛出异常并不起作用,因为ProvideValue
只有在实际加载XAML并创建对象树时才会被调用。
我进行了一些实验,并发现x:Static
的编译器错误消息是BAML编译器完成优化的副产品。实际上,BAML格式具有特定类型的特定成员的概念,因此当XAML包含x:Static
时,编译器实际上会将其替换为一个直接引用成员而不包含类型和方法名称的特殊记录。它通过明确识别StaticExtension类来完成这个操作。TypeExtension也有类似的优化。
我寻找了钩子,希望能够在BAML编译期间调用自己的代码,但是我没有找到任何内容。BAML编译大多数只是将XAML直接转换为对应的二进制格式,其中包括一些特定的优化,但大多数情况下忽略它所看到的内容。
最终,我添加了一个额外的构建步骤,以Microsoft.WinFX.targets
和其他内置目标文件为模型。此步骤扫描我的标记扩展程序的XAML,检查参数,并在它们不正确时生成编译错误。这完全独立于转换为BAML。最终完成这个操作需要几天的额外工作,但我学到了很多。
有关创建自己的.targets文件的注意事项
如果您考虑添加自己的.targets文件,那么您应该知道,除非将目标包含在本地计算机的SafeImports注册表键中,否则Visual Studio和Expression Blend都会抱怨包含您的.targets文件的任何项目。更新此键需要管理员访问权限。根据您的部署方案,这可能是一个问题或不是问题。(例如,全局MSI安装将解决它,或者如果您只有几台开发机器,则可以手动设置该键)。在我的情况下,这并不重要,因为我已经需要自定义的.targets文件用于我在该项目中进行的其他一些操作。
从构建任务记录错误
您不需要IVsErrorList来在Visual Studio中添加错误(如果需要,您将无法正确支持命令行构建、Expression Blend和其他工具)。
您只需要在构建任务内部调用Log.LogError Log.LogWarning,就像这样:
public class CheckForErrorsInMyMarkupExtension : Task
{
... parameters here ...
public override Execute()
{
... code to load XAML and scan it for markup extension errors ...
... when you discover an error ...
Log.LogError("I saw an error");
}
}
有几个VisualStudio集成API可以让您从MEF扩展(仅限VS2010)、VSIntegration包或插件生成自己的诊断消息。
请查看IVsErrorList接口以及IVsOutputWindowPane接口的OutputTaskItemString方法。后者是我在django编辑器中使用的方法。
当然,对这些方法的调用已经嵌入到XAML编译器中了 - 它们基于XAML解析的结果,怎么可能不是呢?