如何正确使用c++ /CLI中实现的类作为.net中数据绑定的数据源

本文关键字:net 数据源 数据绑定 何正确 实现 c++ CLI | 更新日期: 2023-09-27 18:16:22

我在vc++中定义了一个这样的抽象类:

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

我有多个像这样的具体类:

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

我现在想在c#应用程序的ComboBox中选择几个AbstractFoo实现之一。因此,我点击组合框上的小箭头,并勾选"使用数据绑定项"。然后,我尝试创建一个具有AbstractFoo类型的新数据源。当我点击Finish,我得到:

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

当我关闭对话框时,VS退出。当我使用ConcreteFoo时也会发生这种情况。

现在,我能想到的唯一可行的解决方案是在c#中定义一个这样的类:

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 s。

这真的是唯一的方式,还是我宣布什么错误的VS呛?

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

如何正确使用c++ /CLI中实现的类作为.net中数据绑定的数据源

我对此进行了进一步调查,并找到了这个问题的原因。就我目前所知,除了上述的变通办法之外,没有别的解决办法。

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

下面是我如何复制的行为:

首先,我创建了一个c++/CLI类库,其中包含一个非常简单的抽象和具体类(现在我们称它们为AbstractThingConcreteThing)。然后,我创建了一个简单的c# Windows窗体应用程序,其中只包含一个组合框,该组合框以AbstractThing类型绑定到绑定源。这工作。

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

重新创建绑定仍然有效。

现在,让我们来看看关键字:

一旦我添加了一个包含到非托管库,如#include <unmanaged.h>,我得到了上面的错误和VS退出。

为了解决问题,我随后创建了如上所述的包装器,它起初工作,但导致下一个奇怪的错误:当我重新进入GUI设计器时,我得到一个错误页面,我的托管/非托管互操作DLL(包含AbstractThingConcreteThing的DLL)无法找到。这种情况是:.net的数据绑定分析公共属性的类,如果它们中的任何一个恰好是与非托管的东西互操作的类型,事情就会变得疯狂。我相信GUI设计器和VS在错误的目录中查找依赖的非托管dll。

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

因此,AbstractThing类示例的包装器现在可以工作了:
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;