@ Pedery & jmayor: Спасибо за предложения, ребята! (см. мои выводы ниже)
После нескольких экспериментов, проб и ошибок и небольшого "рефлектора" мне удалось выяснить, почему именно я получал загадочное сообщение об ошибке "Ошибка HRESULT E_FAIL возвращена после вызова COM компонент».
Это связано с тем, что при перетаскивании данных WPF <-> Winforms в одном и том же приложении данные должны быть сериализуемыми!
Я проверил, насколько сложно было бы преобразовать все наши классы в "Сериализуемые", и я бы испытал настоящую боль по нескольким причинам ... во-первых, нам нужно было бы практически сделать все классы serializable и два, некоторые из этих классов имеют ссылки на Controls! И элементы управления не сериализуемы. Так что Major рефакторинг был бы необходим.
Итак ... так как мы хотели передать любой объект любого класса для перетаскивания из / в WPF внутри одного и того же приложения, я решил создать класс-оболочку с атрибутом Serializable и реализацией ISerializable. У меня был бы 1 конструктор с 1 параметром типа «объект», который был бы фактическими данными перетаскивания. Эта оболочка, при сериализации / десериализации, будет сериализовать не сам объект ... а скорее IntPtr к объекту (что мы можем сделать, поскольку мы хотим, чтобы эта функциональность существовала только в нашем приложении только с одним экземпляром). См. Пример кода ниже:
[Serializable]
public class DataContainer : ISerializable
{
public object Data { get; set; }
public DataContainer(object data)
{
Data = data;
}
// Deserialization constructor
protected DataContainer(SerializationInfo info, StreamingContext context)
{
IntPtr address = (IntPtr)info.GetValue("dataAddress", typeof(IntPtr));
GCHandle handle = GCHandle.FromIntPtr(address);
Data = handle.Target;
handle.Free();
}
#region ISerializable Members
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
GCHandle handle = GCHandle.Alloc(Data);
IntPtr address = GCHandle.ToIntPtr(handle);
info.AddValue("dataAddress", address);
}
#endregion
}
Чтобы сохранить функциональность IDataObject, я создал следующую оболочку DataObject:
public class DataObject : IDataObject
{
System.Collections.Hashtable _Data = new System.Collections.Hashtable();
public DataObject() { }
public DataObject(object data)
{
SetData(data);
}
public DataObject(string format, object data)
{
SetData(format, data);
}
#region IDataObject Members
public object GetData(Type format)
{
return _Data[format.FullName];
}
public bool GetDataPresent(Type format)
{
return _Data.ContainsKey(format.FullName);
}
public string[] GetFormats()
{
string[] strArray = new string[_Data.Keys.Count];
_Data.Keys.CopyTo(strArray, 0);
return strArray;
}
public string[] GetFormats(bool autoConvert)
{
return GetFormats();
}
private void SetData(object data, string format)
{
object obj = new DataContainer(data);
if (string.IsNullOrEmpty(format))
{
// Create a dummy DataObject object to retrieve all possible formats.
// Ex.: For a System.String type, GetFormats returns 3 formats:
// "System.String", "UnicodeText" and "Text"
System.Windows.Forms.DataObject dataObject = new System.Windows.Forms.DataObject(data);
foreach (string fmt in dataObject.GetFormats())
{
_Data[fmt] = obj;
}
}
else
{
_Data[format] = obj;
}
}
public void SetData(object data)
{
SetData(data, null);
}
#endregion
}
И мы используем вышеперечисленные классы следующим образом:
myControl.DoDragDrop(new MyNamespace.DataObject(myNonSerializableObject));
// in the drop event for example
e.Data.GetData(typeof(myNonSerializableClass));
Я знаю, я знаю ... это не очень довольно ... но оно делает то, что мы хотели. Мы также создали вспомогательный класс dragdrop, который маскирует создание DataObject и имеет шаблонные функции GetData для извлечения данных без какого-либо преобразования ... немного похоже на:
myNonSerializableClass newObj = DragDropHelper.GetData<myNonSerializableClass>(e.Data);
Так что еще раз спасибо за ответы! Вы, ребята, дали мне хорошие идеи, где искать возможные решения!
-Oli