此命名空间冲突是由于 XAML 到 .NET 代码生成中的错误造成的吗?

Is this namespace collision due to a bug in the XAML to .NET code generation?

提问人:Matthew Stewart 提问时间:12/13/2013 最后编辑:Matthew Stewart 更新时间:12/18/2013 访问量:968

问:

下面我将介绍如何重现我收到的错误。它在 VS 2010、2012 和 2013 中的行为相同。正如我在下面指出的那样,将其分解为多个项目很重要。

重现错误的步骤:

  1. 创建解决方案。

  2. 创建一个名为 Common 的 C# 类库,其中包含一个名为 Handler.cs 的文件:

    using System;
    
    namespace Common
    {
        public delegate void Handler(object sender, EventArgs args);
    }
    
  3. 创建一个名为 MyControlLibrary 的 WPF 用户控件库项目,并引用 Common。在其中,创建一个名为 MyControl.xaml 的用户控件。

    MyControl.xaml:

    <UserControl x:Class="ControlNamespace.MyControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         mc:Ignorable="d"
         d:DesignHeight="300" d:DesignWidth="300">
        <Grid>
    
        </Grid>
    </UserControl>
    

    MyControl.xaml.cs:

    using System.Windows.Controls;
    using Common;
    
    namespace ControlNamespace
    {
        public partial class MyControl : UserControl
        {
            public MyControl()
            {
                InitializeComponent();
            }
    
            public event Handler MyEvent;
        }
    }
    
  4. 创建一个名为 MyWpfApplication 的 WPF 应用程序项目,并引用 Common 和 MyControlLibrary。在其中,创建 WindowNamespace.Common.cs 以及一个名为 MyWindow.xaml 的窗口。

    WindowNamespace.Common.cs:

    namespace WindowNamespace.Common
    {
    }
    

    MyWindow.xaml:

    <Window x:Class="WindowNamespace.MyWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:c="clr-namespace:ControlNamespace;assembly=WpfControlLibrary1"
            Title="MyWindow" Height="300" Width="300">
        <Grid>
            <c:MyControl MyEvent="MyControl_MyEvent" />
        </Grid>
    </Window>
    

    MyWindow.xaml.cs:

    using System;
    using System.Windows;
    
    namespace WindowNamespace
    {
        public partial class MyWindow : Window
        {
            public MyWindow()
            {
                InitializeComponent();
            }
    
            void MyControl_MyEvent(object sender, EventArgs args)
            {
            }
        }
    }
    
  5. 生成解决方案。

您应收到以下错误,指向 MyWindow.xaml 的第 7 行:

类型或命名空间名称“Handler”在命名空间中不存在 “WindowNamespace.Common”(是否缺少程序集引用?

如果打开为 MyWindow.xaml 生成的 .g.i.cs 文件,则应在 IComponentConnector.Connect 方法中看到以下内容:

#line 7 "..\..\MyWindow.xaml"
((ControlNamespace.MyControl)(target)).MyEvent += new Common.Handler(this.MyControl_MyEvent);

问题的根源是它试图在 WindowNamespace 中查找 Common.Handler。这可以通过将其生成为以下方式来解决:

#line 7 "..\..\MyWindow.xaml"
((ControlNamespace.MyControl)(target)).MyEvent += new global::Common.Handler(this.MyControl_MyEvent);

或者通过在文件顶部添加 use:

using Common;

...

#line 7 "..\..\MyWindow.xaml"
((ControlNamespace.MyControl)(target)).MyEvent += new Handler(this.MyControl_MyEvent);

请注意,如果所有这些源文件都捆绑到单个项目中,则错误会消失,因为 .g.i.cs 文件的生成方式不同(即它不会显式将处理程序添加到事件中)。

这实际上是 XAML->.NET 翻译中的错误,还是我做错了什么?

C# .NET WPF XAML 命名空间

评论

1赞 John Fisher 1/13/2015
感谢您为重现此问题所做的努力。可惜目前还没有任何解决方案。似乎一些 clr-namespace:... 调整以允许命名空间中的 global: 可以解决问题。

答:

0赞 Mark Feldman 12/18/2013 #1

如果在 MyWpfApplication 的 WindowNamespace.Common 命名空间声明中重新声明 Handler 委托并尝试编译,则会出现什么情况:

Error   1   Cannot implicitly convert type 'WindowNamespace.Common.Handler' to 'Common.Handler' c:\Dev\YourSolution\MyWpfApplication\MyWindow.xaml  7   63  MyWpfApplication

Common 项目声明一个名为“Common”的全局命名空间,您的控件库也在使用该命名空间。但是,当应用程序显式声明“WindowNamespace.Common”时,它会创建一个本地命名空间,而该命名空间恰好与父控件所在的命名空间相同。这实际上会产生编译器错误 CS0433 的 Visual Studio 文档中描述的歧义问题。

将 MyWpfApplication 中的通用命名空间声明更改为“通用”,问题将消失。

评论

0赞 Matthew Stewart 12/18/2013
您对命名空间冲突的性质是正确的,它假设 Common 指的是当前命名空间中存在的 Common,而不是全局 Common。但是,共享相同名称的两个命名空间是......常见,并且 C# 提供了解决这些冲突的机制,而无需重命名其中一个冲突。在这种情况下,这些机制根本无法使用,因为我不是编写 C# 的人,除非 XAML 公开了执行此操作的方法。
0赞 Mark Feldman 12/18/2013
我想你已经考虑过并拒绝了混叠?您可能需要提供更多详细信息,然后才能说明您可以控制哪些部分。无论哪种方式,我都怀疑这算作编译器错误,它使用的是您给它的命名空间。您不能将事件绑定到 ICommand 或其他东西并在代码中解决冲突吗?
0赞 Matthew Stewart 12/18/2013
我不清楚混叠在这里有什么帮助;你能澄清一下吗?我没有指定无法解析的类型,因此我没有机会提供命名空间别名。这仅在生成的代码中指定,以根据 XAML 事件绑定分配事件处理程序。