IDataObject存储托管对象引用

时间:2015-07-16 21:10:24

标签: serialization drag-and-drop c++-cli pass-by-reference pinning

我正在尝试使用标准的WinForms和WPF(托管)API在我的C ++ / CLI应用程序中实现拖放功能。这些API接受包装在IDataObject实现中的对象,对其进行序列化,然后在指定了拖放目标后进行反序列化。我不希望数据传输序列化和反序列化。

更具体一点(虽然大大简化):

[SerializableAttribute]
ref class MyType : public System::IObserver<Object^>
{
public:
    System::IObservable<Object^> ^myObj;
    static void Watch(MyType ^wrapper)
    {
        myObj->Subscribe(watcher);
    }
private:
    static MyType ^watcher = gcnew MyType();
    void OnCompleted(void) = System::IObserver<Object^>::OnCompleted {}
    void OnError(System::Exception^) = System::IObserver<Object^>::OnError {}
    void OnNext(Object^) = System::IObserver::OnNext
    {
        System::Windows::Forms::MessageBox::Show("Hi!");
    }
}
ref class MyControl : public System::Windows::Controls::UserControl
{
public:
    MyControl(void)
    {
        this->Drop += gcnew DragEventHandler(this, &MyControl::this_Drop);
    }
private:
    void this_Drop(Object^, System::Windows::DragEventArgs ^e)
    {
        MyType::Watch(dynamic_cast<MyType^>(e->Data->GetData("MyFormat")));
    }
}
ref class MyForm : public System::Windows::Forms::Form
{
public:
    MyForm(void)
    {
        InitializeComponent();
        myTreeView->ItemDrag += gcnew System::Windows::Forms::ItemDragEventHandler(this, &MyForm::myTreeView_ItemDrag);
    }
private:
    MyType ^data = gcnew MyType();
    System::Windows::Forms::TreeView ^myTreeView;
    MyControl ^myControl;
    void modifyMyObjField(MyType^);
    void myEventHandler(Object^, EventArgs^)
    {
        modifyMyObjField(data);
    }
    void myTreeView_ItemDrag(Object^, System::Windows::Forms::ItemDragEventArgs^)
    {
        myTreeView->DoDragDrop(gcnew DataObject("MyFormat", MyType), DragDropEffects::Copy);
    }
}

调用myEventHandler时,不会显示任何消息框,因为另一个MyType对象从已修改的对象接收IObservable订阅。

因为所有的拖放都发生在 cis - 应用程序中,所以我可以通过固定MyForm::data并来回传递IntPtr来解决此问题。 MyForm::myTreeView_ItemDrag成为

{
    myTreeView->DoDragDrop(gcnew DataObject("MyFormat", System::Runtime::InteropServices::GCHandle::Alloc(data, System::Runtime::InteropServices::GCHandleType::Pinned).ToIntPtr()), DragDropEffects::Copy);
}

MyControl::this_Drop变为

{
    System::Runtime::InteropServices::GCHandle handle = System::Runtime::InteropServices::GCHandle::FromIntPtr(*dynamic_cast<IntPtr^>(e->Data->GetData("MyFormat")));
    MyType::Watch(dynamic_cast<MyType^>(handle.Target));
    handle.Free();
}

这似乎是完成一项简单任务的极其复杂的方法,并且(显然)会使垃圾收集器陷入困境。有没有更好的方法让我失踪?

0 个答案:

没有答案