views:

233

answers:

2

I'm attempting to allow my users to drag and drop certain rows of data from one custom list control to another, where the second list control is in another instance of the same application.

DoDragDrop(parameterTypedListView.SelectedObjects, DragDropEffects.Copy);

where parameterTypedListView.SelectedObjects is a generic IList where T is a custom class containing only valuetypes as fields/properties.

In the OnDragDrop event I try to extract this data but only get a System.__ComObject ... object which seems to inherit from System.MarshalByRefObject.

In short: How do I extract the data in an object oriented format I can actually use?

Edit: Setting my custom class as serializable has no discernible effect whatsoever. I can enumerate the __ComObject:

foreach (var dataObject in (IEnumerable) e.Data.GetData("System.Collections.ArrayList"))
{
    // this actually enumerates the correct number of times, i.e. as many times as there are items in the list.
}

but every dataObject is, in itself, a System.__ComObject that I cannot cast to anything useful.

+1  A: 

I was able to replicate your initial problem, but as soon as I added the [Serializable] attribute to the class in the array list, I was able to see the objects as their correct type.

Here is some example code, showing a small working example.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        this.DragDrop += new System.Windows.Forms.DragEventHandler(this.Form1_DragDrop);
        this.DragEnter += new System.Windows.Forms.DragEventHandler(this.Form1_DragEnter);
    }

    [Serializable]
    class DragClass
    {
        public string Prop1 { get; set; }
        public int Prop2 { get; set; }
    }

    private void label1_MouseDown(object sender, MouseEventArgs e)
    {
        System.Collections.ArrayList aDragClasses = new System.Collections.ArrayList();
        aDragClasses.Add(new DragClass() { Prop1 = "Test1", Prop2 = 2 });
        aDragClasses.Add(new DragClass() { Prop1 = "Test2", Prop2 = 3 });
        aDragClasses.Add(new DragClass() { Prop1 = "Test3", Prop2 = 4 });

        DoDragDrop(aDragClasses, DragDropEffects.Copy);
    }

    private void Form1_DragEnter(object sender, DragEventArgs e)
    {
        e.Effect = DragDropEffects.Copy;
    }

    private void Form1_DragDrop(object sender, DragEventArgs e)
    {
        foreach (var aData in (System.Collections.IEnumerable)e.Data.GetData(typeof(System.Collections.ArrayList)))
        {
          System.Diagnostics.Debug.WriteLine(((DragClass)aData).Prop1);
        }
    }



}
Rick Mogstad
A: 

I think that the problem is that you are using the list directly to pass the data. I tried it several different ways to get it to fail and figured out a few ways that it doesn't work.

If you don't have the [Serializable] attribute on your custom classes it will not work correctly because this is how the classes are marshaled between the processes. Also, if I use a List directly to pass the data I get a null reference exception.

If you use a simple transport class to pass the data (and all the types are serializable) then everything worked fine for me.

[Serializable]
class Test
{
    public string Name { get; set; }
    public string Description { get; set; }
}

[Serializable]
class Transport
{
    public Transport()
    {
        this.Items = new List<Test>();
    }
    public IList<Test> Items { get; private set; }
}

Then I can do this no problem and it works across instances...

private void Form1_DragDrop(object sender, DragEventArgs e)
{
    foreach (var item in ((Transport)e.Data.GetData(typeof(Transport))).Items)
    {
        System.Diagnostics.Debug.WriteLine(item.Name + " " + item.Description);
    }
}
Brian ONeil