標準の 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 サブスクリプションを受け取るためです。
すべてのドラッグ アンド ドロップはcisMyForm::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();
}
これは、単純なタスクを実行するのに非常に複雑な方法のように思われ、(明らかに) ガベージ コレクターを停止させます。私が見逃しているより良い方法はありますか?