9

This question is close to what I'm interested in, but not quite.

I have a .NET WinForms application written in C#. I have a ListView control which displays an array of C# objects. I've hooked it up so that you can drag/drop these listview items to a different form in the same application, and it properly passes the array of objects (type Session) to the drop handler for that other form.

However, I now want to support cross-process drag/drop where I run multiple instances of my application. This appears that it's going to work (e.g. GetDataPresent succeeds), but ultimately throws an exception when I actually try to retrieve the data-- cannot cast object[] to Session[].

if (e.Data.GetDataPresent("Fiddler.Session[]"))
{
   Session[] oDroppedSessions;
   try
   {
      oDroppedSessions = (Session[])e.Data.GetData("Fiddler.Session[]");
   }
   catch (Exception eX)
   {  // reaches here 
   }
}

Anyone know if I must implement ISerializable for my objects in order to make this work? Ordinarily, I'd simply try it, but implementing ISerializable for this class would be quite non-trivial, and I'm worried that there may be weird side-effects of doing so.


UPDATE: Implementing ISerializable doesn't help-- the method is never called. Similarly, adding the Serializable attribute to the class has no impact at all. Any other ideas?

Micha Wiedenmann
  • 19,979
  • 21
  • 92
  • 137
EricLaw
  • 56,563
  • 7
  • 151
  • 196

3 Answers3

6

You are crossing a process boundary, object references are not valid in another process. The DataObject class supports serializing objects to get them across the wall, it uses BinaryFormatter. So, yes, you'll need to apply the [Serializable] attribute to your class and make sure your objects can de/serialize properly.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Yeah, that's what I was afraid of. Any idea if I'm going to introduce performance regressions if I implement ISerializable? The binary serialization of this object might be hundreds of KB. – EricLaw Jan 21 '10 at 19:26
  • Let us know when you find out please. – Hans Passant Jan 21 '10 at 19:44
  • Hmmm... implementing ISerializable doesn't help-- the method is never called. Similarly, adding the Serializable attribute to the class has no impact at all. Any other ideas? – EricLaw Jan 24 '10 at 20:20
  • 2
    Use DataFormat.Serializable to trigger the serialization code. – Hans Passant Jan 24 '10 at 20:29
  • It turns out that if I add both ISerializable AND the Serializable attribute, and put a MessageBox in the ISerializable implementation, *then* I see it get hit. If I simply let my ISerializable implementation emit a Not Yet Implemented exception, that exception gets eaten somewhere along the way and I still get the old "cannot convert object[] to Session[]" exception. So, now I've just got to write a bunch of code to make my ISerializable implementation work. Thanks for your help! – EricLaw Jan 25 '10 at 18:02
  • @HansPassant I've ran into this issue while doing drag & drop between two separate processes. I fixed it by doing `var test = myDragEventArgs.Data.GetData(DataFormats.Serializable) as MyDataObject; if (test != null) {/* do stuff */}`, but it feels really ugly / error prone / etc. Another way to fix it was to do `if (myDragEventArgs.Data.GetDataPresent("MyAssembly.MyDataObject")) {/* do stuff */}`, but here I am giving up type safety, which I do not want. Is there any smarter way to force `GetDataPresent` to trigger serialization in this case? – Mihai Todor Jun 05 '14 at 09:56
  • Please point me to an example of dragging and dropping a C# object (my class with data in it) from one process to another. I want to be able to have one process that acquires data, and allow the user to be able to drag that data in to a second process that plots the data. I have been trying to implement this, but it isn't working. – Curt Nov 15 '19 at 23:20
0

Ok this is a shot, instead of using a whole array of Sessions, try doing it individually like this...

   Session[] oDroppedSessions;
   try
   {
      if (e.Data.GetData("Fiddler.Session[]") != null){
          object[] objs = e.Data.GetData("Fiddler.Session[]");
          if (objs != null && objs.Length > 1){
             oDroppedSessions = new Session[objs.Length];
             int nIndex = 0;
             foreach(object obj in objs){
                if (obj is Session){
                  oDroppedSessions[nIndex] = (Session)obj;
                  nIndex++;
                }
             }
          }
      }
   }
   catch (Exception eX)
   {  // reaches here }

Worth a shot, other than shooting myself in the foot as I do not fully understand the Session part, try it...

Hope this helps, Best regards, Tom.

t0mm13b
  • 34,087
  • 8
  • 78
  • 110
-1

You could use "as" for casting which will avoid the exception ("as" will return "null" without throwing an exception if the cast fails) - but I don't think this will solve your problem (it will just avoid the actual exception), as I agree it's likely you'll have to make your class Serializable. You could test your hypothesis by commenting out the fields that will be harder to make it work - just for now to test it.

Andy Jacobs
  • 933
  • 3
  • 10
  • 18
  • 1
    -1: Trading an `InvalidCastException` for a `NullReferenceException` is a loss of information. The `as` keyword is good if you expect that a cast *might* fail. Otherwise, it's bad, and I've seen it overused a lot. – P Daddy Jan 21 '10 at 18:12