如何正确使用在 C++/CLI 中实现的 class 作为 .net 中数据绑定的数据源?

How to correctly use a class implemented in C++/CLI as a data source for data binding in .net?

我在 VC++ 中定义了一个抽象 class,如下所示:

public ref class AbstractFoo abstract {
public:
   virtual property String^ Bar {
       virtual String^ get() = 0;
   }

   // More stuff
};

我有多个具体的 class 是这样的:

public ref class ConcreteFoo : AbstractFoo {
public:
    property String^ Bar {
        virtual String^ get() override;
    }
    // more
}

我现在想 select 在 C# 应用程序的 ComboBox 中实现几个 AbstractFoo 之一。因此,我单击组合框上的小箭头并选中 "Use Data Bound items"。然后我尝试创建一个 AbstractFoo 类型的新数据源。然后单击 Finish 时,我得到:

Error using the dropdown: Object reference not set to an instance of an object.

当我关闭对话框时,VS 退出。当我使用 ConcreteFoo.

时也会发生这种情况

目前,我能想到的唯一可行的解​​决方案是在 C# 中定义一个 class,如下所示:

internal sealed class FooWrapper {

    private readonly AbstractFoo _foo;

    internal FooWrapper(AbstractFoo foo) {
        _foo = foo;
    }

    public String DisplayName { get { return _foo.Bar; } }

    public static implicit operator AbstractFoo(FooWrapper w) {
        return w._foo;
    }
}

然后添加这些 FooWrappers 并使用隐式转换取回 AbstractFoo

这真的是唯一的方法吗,还是我在 VS 卡住的地方声明了错误?

编辑:创建 GUI 时,ConcreteFoo 实现已经存在。

我对此进行了更多调查,并找到了导致此问题的原因。据我目前所知,除了上述解决方法外,没有其他解决方案。

它与托管/非托管互操作有关。我在这个项目中仍然绑定到 VS2010,所以我不知道这只是那里的一个错误还是我配置错误。

这是我重现该行为的方式:

首先,我创建了一个 C++/CLI class 库,其中包含非常简单的抽象和具体 class(我们暂时称它们为 AbstractThingConcreteThing)。然后,我创建了一个简单的 C# Windows Forms 应用程序,其中仅包含一个组合框,该组合框绑定到具有 AbstractThing 类型的绑定源。这有效。

然后我像往常一样将依赖项添加到非托管库:将非托管库的包含目录指定为附加包含目录,该目录包含 unmanaged.libunmanaged.dll 两者调试和发布模式,并添加 unmanaged.lib 作为附加库。然后,我在 C# 应用程序中添加了一个 post-build 命令,该命令在成功构建后将适当的 unmanaged.dll 复制到构建目录中。

重新创建绑定仍然有效。

现在,进入游戏破坏者:

当我向非托管库添加一个包含 #include <unmanaged.h> 时,我得到了上述错误并且 VS 退出了。

为了解决问题,我然后创建了一个如上所述的包装器,它起初有效,但导致了下一个奇怪的错误:当我重新进入 GUI 设计器时,我得到一个错误页面找不到我的 managed/unmanaged 互操作 DLL(包含 AbstractThingConcreteThing 的 DLL)。案例是:.net 的数据绑定分析 classes 的 public 属性,如果它们中的任何一个恰好属于与非托管内容互操作的类型,事情就会变得疯狂。我相信 GUI 设计器和 VS 在错误的目录中查找依赖的非托管 DLL。

因此,唯一可行的方法是编写包装器并通过使用内部 属性 或方法显式提取来隐藏数据绑定中的互操作内容。

因此,示例 AbstractThing class 的包装器现在可以工作了:

internal sealed class ThingWrapper {

    private readonly AbstractThing _thing;

    internal ThingWrapper(AbstractThing thing) {
        _thing = thing;
    }

    public String DisplayName { get { return _thing.SomeStringProperty; } }

    internal AbstractThing Thing { get { return _thing; } }
}

制作internal AbstractThing Thing属性public导致设计器无法正确加载,所以无法使用绑定源的ValueMember属性。自 AbstractThing theThing = ((ThingWrapper) theComboBox.SelectedItem).Thing;

起必须手动完成提取