gpt4 book ai didi

wpf - WinForms互操作,从WinForms-> WPF拖放

转载 作者:行者123 更新时间:2023-12-03 14:01:17 25 4
gpt4 key购买 nike

我试图从“ ElementHost”中包含的WPF控件上的应用程序的Winforms部分中拖动数据。当我尝试这样做时,它就会崩溃。

尝试相同的方法,但是从Winforms到Winforms都可以正常工作。 (请参见下面的示例代码)

我需要进行这项工作的帮助...有任何线索我做错了吗?

谢谢!



例:
在下面的示例代码中,我只是试图拖动在1)System.Windows.Forms.TextBox(Winforms)和2)System.Windows.TextBox(WPF)上的标签控件上启动拖动时创建的自定义MyContainerClass对象。 ,添加到ElementHost中)。

情况1)工作正常,但情况2)在尝试使用GetData()检索放置数据时崩溃。 GetDataPresent(“ WindowsFormsApplication1.MyContainerClass”)返回“ true”,因此从理论上讲,我应该能够像Winforms一样检索该类型的放置数据。

这是崩溃的堆栈跟踪:

"Error HRESULT E_FAIL has been returned from a call to a COM component" with the following stack trace: at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo) at System.Windows.Forms.DataObject.GetDataIntoOleStructs(FORMATETC& formatetc, STGMEDIUM& medium) at System.Windows.Forms.DataObject.System.Runtime.InteropServices.ComTypes.IDataObject.GetDataHere(FORMATETC& formatetc, STGMEDIUM& medium) at System.Windows.Forms.DataObject.System.Runtime.InteropServices.ComTypes.IDataObject.GetData(FORMATETC& formatetc, STGMEDIUM& medium) at System.Windows.DataObject.OleConverter.GetDataInner(FORMATETC& formatetc, STGMEDIUM& medium) at System.Windows.DataObject.OleConverter.GetDataFromOleHGLOBAL(String format, DVASPECT aspect, Int32 index) at System.Windows.DataObject.OleConverter.GetDataFromBoundOleDataObject(String format, DVASPECT aspect, Int32 index) at System.Windows.DataObject.OleConverter.GetData(String format, Boolean autoConvert, DVASPECT aspect, Int32 index) at System.Windows.DataObject.OleConverter.GetData(String format, Boolean autoConvert) at System.Windows.DataObject.GetData(String format, Boolean autoConvert) at System.Windows.DataObject.GetData(String format) at WindowsFormsApplication1.Form1.textBox_PreviewDragEnter(Object sender, DragEventArgs e) in WindowsFormsApplication1\WindowsFormsApplication1\Form1.cs:line 48  

Here is some code:

// -- Add an ElementHost to your form --
// -- Add a label to your form --

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();

System.Windows.Controls.TextBox textBox = new System.Windows.Controls.TextBox();
textBox.Text = "WPF TextBox";
textBox.AllowDrop = true;
elementHost2.Child = textBox;
textBox.PreviewDragEnter += new System.Windows.DragEventHandler(textBox_PreviewDragEnter);

System.Windows.Forms.TextBox wfTextBox = new System.Windows.Forms.TextBox();
wfTextBox.Text = "Winforms TextBox";
wfTextBox.AllowDrop = true;
wfTextBox.DragEnter += new DragEventHandler(wfTextBox_DragEnter);
Controls.Add(wfTextBox);
}

void wfTextBox_DragEnter(object sender, DragEventArgs e)
{
bool dataPresent = e.Data.GetDataPresent("WindowsFormsApplication1.MyContainerClass");

// NO CRASH here!
object data = e.Data.GetData("WindowsFormsApplication1.MyContainerClass");
}

void textBox_PreviewDragEnter(object sender, System.Windows.DragEventArgs e)
{
bool dataPresent = e.Data.GetDataPresent("WindowsFormsApplication1.MyContainerClass");

// Crash appens here!!
// {"Error HRESULT E_FAIL has been returned from a call to a COM component."}
object data = e.Data.GetData("WindowsFormsApplication1.MyContainerClass");
}

private void label1_MouseDown(object sender, MouseEventArgs e)
{
label1.DoDragDrop(new MyContainerClass(label1.Text), DragDropEffects.Copy);
}
}

public class MyContainerClass
{
public object Data { get; set; }

public MyContainerClass(object data)
{
Data = data;
}
}

最佳答案

@Pedery&jmayor:谢谢你们的建议! (请参阅下面的发现)

经过大量的试验,反复试验和一些“反射”后,我设法弄清楚为什么我收到了一个隐式错误消息“从调用COM组件返回了错误HRESULT E_FAIL”。

这是由于在同一应用程序中拖动数据WPF <-> Winforms时,该数据必须可序列化!

我已经检查了将所有类转换为“可序列化”的难易程度,由于两个原因,我会感到非常痛苦……一个,我们实际上需要使所有类都可序列化,而另外两个,其中一些类引用了控件!而且控件不可序列化。因此,将需要进行重大的重构。

所以...由于我们要传递任何类的任何对象以在同一应用程序内从WPF拖放到WPF,因此我决定创建一个具有Seri​​alizable属性的包装类并实现ISerializable。我将有1个构造函数,其中1个参数为“ object”类型,这将是实际的拖动数据。该包装器在进行序列化/反序列化时,不会序列化对象本身……而是序列化到对象的IntPtr(我们可以这样做,因为我们只希望在1个实例的应用程序中具有该功能。)请参见下面的代码示例:

[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));


我知道我知道...这不是很漂亮...但是它正在做我们想要的。我们还创建了一个拖放类帮助器类,该类可屏蔽DataObject的创建,并具有模板化的GetData函数来检索数据而无需进行任何强制转换……有点像:

myNonSerializableClass newObj = DragDropHelper.GetData<myNonSerializableClass>(e.Data);


因此,再次感谢您的答复!你们给了我好主意,在哪里寻找可能的解决方案!

-奥利

关于wpf - WinForms互操作,从WinForms-> WPF拖放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1213074/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com