WPF标记扩展如何引发编译错误?

6

某些标记扩展会引发编译错误。例如,如果找不到所引用的类,则StaticExtension(x:Static)会引发编译错误。有人知道这是什么机制吗?它是内置在XAML编译器中还是可用于自定义标记扩展的功能?

编辑:下面的mfeingold建议我查看IVsErrorList接口,但我无法立即看出如何帮助编写生成编译时错误的标记扩展。有示例吗?

2个回答

7

扩展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");
  }
}

0

有几个VisualStudio集成API可以让您从MEF扩展(仅限VS2010)、VSIntegration包或插件生成自己的诊断消息。

请查看IVsErrorList接口以及IVsOutputWindowPane接口的OutputTaskItemString方法。后者是我在django编辑器中使用的方法。

当然,对这些方法的调用已经嵌入到XAML编译器中了 - 它们基于XAML解析的结果,怎么可能不是呢?


这些接口是在VS2010中新增的吗?当我说“内置”的时候,我的意思是VS是否具有关于可能导致编译时错误的个别标记扩展的特定知识,或者是否可以通过使用接口、属性等来进行扩展。你的回答似乎表明对于VS2008而言是如此,但已经为VS2010打开了。这样正确吗? - Grokys
不过自从VS2005以来,这些接口就已经存在了。MEF扩展是一种新的、更好的扩展Visual Studio的方式。 - mfeingold
嗯,我看了 IVsErrorList 的文档,但仍然不明白如何实现自定义标记扩展来生成编译时错误。更新问题以请求示例... - Grokys

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接