0

我正在尝试使用标准 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传递来解决这个问题。变成IntPtrMyForm::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();
}

这似乎是完成一项简单任务的一种非常复杂的方法,并且(显然)会使垃圾收集器陷入困境。我错过了更好的方法吗?

4

0 回答 0