Silverlight ListBoxDragDropTarget, why cant I drop there?

In my opinion Microsoft has slipped up when implementing the Silverlight DragDropTarget, whether intended or not.

I was having an issue last week where I had 2 list boxes bound to separate ObservableCollections of the same type; let’s say IFoo, and a concrete implementation class, Foo. When dragging items between the 2 list boxes I would be shown the red invalid icon even though AllowedSourceEffect=Link was enabled. To find out what was happening I inspected the System.Windows.Controls.Toolkit assembly with Jetbrains dotPeek to discover that the CanAddItem method, which gets continually evaluated with the mouse drag movement, calls through to a method called CanInsert in a CollectionHelper class which is as follows:


public static bool CanInsert(this IEnumerable collection, object item)
    {
      ICollectionView collectionView = collection as ICollectionView;
      if (collectionView != null)
        return CollectionHelper.CanInsert(collectionView.SourceCollection, item);
      if (CollectionHelper.IsReadOnly(collection))
        return false;
      Type type = Enumerable.FirstOrDefault(Enumerable.Where((IEnumerable) collection.GetType().GetInterfaces(), (Func) (interfaceType => interfaceType.FullName.StartsWith("System.Collections.Generic.IList`1", StringComparison.Ordinal))));
      if (type != null)
        return type.GetGenericArguments()[0] == item.GetType();
      if (collection is IList)
        return true;
      else
        return false;
    }

I would like to say that the reflection to determine the type is an awful line of code, using a string to check that a collection is being used is pretty ugly to say the least.

The problem lies with the return statement of the 3rd condition. This is where the method will usually return from, using the == operator which does a direct comparison of the types. In my case IFoo is not exactly the same type as Foo despite it implementing the interface. Problem! To resolve this I created my own implementation of ListBoxDragDropTarget which overwrites the CanInsert method and instead of using the == operator; I check whether the type IsAssignableFrom:


using System;
using System.Collections;
using System.ComponentModel;
using System.Linq;
using System.Windows.Controls;

namespace SilverlightDragDrop
{
    public class FixedListBoxDragDropTarget : ListBoxDragDropTarget
    {
        protected override bool CanAddItem(ListBox itemsControl, object data)
        {
            if (itemsControl.ItemsSource == null)
                return true;
            bool canInsert = CanInsert(itemsControl.ItemsSource, data);
            return canInsert;
        }

        private static bool CanInsert(IEnumerable collection, object data)
        {
            ICollectionView collectionView = collection as ICollectionView;
            if (collectionView != null)
                return CanInsert(collectionView.SourceCollection, data);
            Type type = collection.GetType().GetInterfaces().Where(interfaceType => interfaceType.FullName.StartsWith("System.Collections.Generic.IList`1", StringComparison.Ordinal)).FirstOrDefault();
            if (type != null)
                return type.GetGenericArguments()[0].IsAssignableFrom(data.GetType());
            return collection is IList;
        }
    }
}

Problem solved.

3 Thoughts on “Silverlight ListBoxDragDropTarget, why cant I drop there?

  1. Excellent solution. Lovely. Yoink! ;-)

  2. jehof on May 16, 2012 at 9:20 am said:

    This problem drived me crazy until i found your blog post. Thanks for providing the solution.

  3. Thanks a lot for the post. It would take me forever to track down the issue if wasn’t for your post.

Leave a Reply

Your email address will not be published. Required fields are marked *

Please type the characters of this captcha image in the input box

Please type the characters of this captcha image in the input box

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Post Navigation