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