我正在尝试使用标准 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();
}
这似乎是完成一项简单任务的一种非常复杂的方法,并且(显然)会使垃圾收集器陷入困境。我错过了更好的方法吗?