locked
ListView Drop event not firing RRS feed

  • Question

  • Hello all,

    I have a ListView defined as such:

                   

    <ListView x:Name="videoListView" Grid.Row="1" CanDragItems="True" CanReorderItems="True" AllowDrop="True" IsEnabled="True" Margin="36,0,0,0" SelectionMode="Single"/>

    ...that contains a collection of Image controls. I can drag them around and when I drop them they reorder properly in the UI, but no Drop event ever fires. The goal is simply to catch when the user rearranges the controls in the ListView and then rearrange an internal data structure to match, am I going about this the wrong way?

    EDIT:

    Worked around the first problem by using (abusing?) the Image.Tag attribute to store my metadata, thus avoiding the need for the structure that needed updating in the first place. I still don't understand why the event fails to fire, though.



    • Edited by Matthew Saunier Thursday, March 15, 2012 3:37 PM Second thread started for other issue
    Tuesday, March 6, 2012 3:56 AM

Answers

  • EDIT:

    Worked around the first problem by using (abusing?) the Image.Tag attribute to store my metadata, thus avoiding the need for the structure that needed updating in the first place. I still don't understand why the event fails to fire, though.

    That's an ingenious solution, but I'm not looking forward to finding some ingenious workaround for every ordered list I want to display in a ListView. Out of curiosity, did you try explicitly setting two-way binding? (I'm not optimistic, but it would be cool if that worked.) What about using the HandledEventsToo flag on the AddHandler method?


    Rebecca M. Riordan

    Friday, March 9, 2012 2:25 PM
  • Rebecca, thank you for the hint! This code does work:

            DragEventHandler OnDropEvent = new DragEventHandler(OnDropHandler);
    
            public MainPage()
            {
                this.InitializeComponent();
                videoListView.AddHandler(Control.DropEvent, OnDropEvent, true);
            }
    
            private static void OnDropHandler(object sender, DragEventArgs e)
            {
                //do stuff
            }

    It still seems very broken that subscribing to ListView.Drop apparently does nothing, but this is a beta, so hopefully that will change.


    No matter where you go, there you are. -Buckaroo Banzai



    Friday, March 9, 2012 5:56 PM

All replies

  • Hi Matthew,

    I suspect the first is because the ListView is handling the UIElement's Drop event itself as part of its reordering.

    The second sounds like a bug. Without having debugged it, my guess is that the indices are getting thrown off by the removals. If you remove the items from last to first do you get more better results?

    --Rob

    Tuesday, March 6, 2012 11:14 PM
    Moderator
  • Hello Rob,

    ListView is insensitive to the removal order, it glitches either way. 

    As regards the Drop event, I'm not seeing a way to manipulate ListView.base in any way from code; is there a way to change this behavior? Even though I've hacked my way around not having it, it could definitely make my life easier and my UI more responsive.


    No matter where you go, there you are. -Buckaroo Banzai

    Wednesday, March 7, 2012 7:40 AM
  • For the second issue can you provide a repro with more source? I believe what is happening is that as you remove the item the selected collection gets changes causing problems in the foreach.

    For the first item you would need to derive from ListView and override OnDrop to get the drop notification before the ListView handles it.

    -mark
    Program Manager
    Microsoft

    Thursday, March 8, 2012 7:52 PM
  • Certainly, here is a copy of my project; let me know when I can take it down. I will look into overriding OnDrop; I did try making ListView's backing store an ObservableCollection, but that broke the animations and threw some very nasty exceptions, so I assume that that's a Bad Idea.

    Project archive


    No matter where you go, there you are. -Buckaroo Banzai


    Thursday, March 8, 2012 8:50 PM
  • I get a very strange error if I bind ListView to an ObservableCollection and try to add an item:

            ObservableCollection<object> videoListCollection = new ObservableCollection<object>();

            public MainPage()
            {
                this.InitializeComponent();
                videoPlayer.MediaFailed += MediaFailed;
                videoListView.ItemsSource = videoListCollection;
                videoListCollection.CollectionChanged += videoListCollection_CollectionChanged;
            }

    ...then videoListView.Add(someObject);

    System.Exception was unhandled by user code
      HResult=-2147418113
      Message=Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))
      Source=mscorlib
      StackTrace:
           at System.Runtime.InteropServices.WindowsRuntime.IVector`1.Append(T value)
           at System.Runtime.InteropServices.WindowsRuntime.VectorToCollectionAdapter.Add[T](T item)
           at Phorcys.MainPage.<plusButton_Click>d__0.MoveNext() in c:\Users\Matt\Documents\Visual Studio 11\Projects\Phorcys\Phorcys\MainPage.xaml.cs:line 86
      InnerException: 

    Catastrophic failure and mscorlib is involved? Even if my code is bad, should this ever happen?


    No matter where you go, there you are. -Buckaroo Banzai

    Friday, March 9, 2012 7:21 AM
  • EDIT:

    Worked around the first problem by using (abusing?) the Image.Tag attribute to store my metadata, thus avoiding the need for the structure that needed updating in the first place. I still don't understand why the event fails to fire, though.

    That's an ingenious solution, but I'm not looking forward to finding some ingenious workaround for every ordered list I want to display in a ListView. Out of curiosity, did you try explicitly setting two-way binding? (I'm not optimistic, but it would be cool if that worked.) What about using the HandledEventsToo flag on the AddHandler method?


    Rebecca M. Riordan

    Friday, March 9, 2012 2:25 PM
  • Rebecca, thank you for the hint! This code does work:

            DragEventHandler OnDropEvent = new DragEventHandler(OnDropHandler);
    
            public MainPage()
            {
                this.InitializeComponent();
                videoListView.AddHandler(Control.DropEvent, OnDropEvent, true);
            }
    
            private static void OnDropHandler(object sender, DragEventArgs e)
            {
                //do stuff
            }

    It still seems very broken that subscribing to ListView.Drop apparently does nothing, but this is a beta, so hopefully that will change.


    No matter where you go, there you are. -Buckaroo Banzai



    Friday, March 9, 2012 5:56 PM
  • Glad that helped. It's expected behavior, though, with RoutedEvents. ButtonBase does the same thing with the Tap event that it "eats" to generate Click.

    Rebecca M. Riordan

    Friday, March 9, 2012 7:39 PM
  • While maybe not helpful at first, the reason you do not receive the Drop event is that the ListView/GridView itself handles the Drop event. This was a conscious choice to handle the event during reorder since the ListView/GridView is actually handling the event to perform the reorder. Use the two methods mentioned in this thread (override OnDrop method or use AddHandler to get handled events) is the correct approach.

    Also to mention - you can listen to the DragItemsStarting event on ListView/GridView to know when a reorder/drag is starting. In that event args you will get the list of items being dragged.
    In addition the issues about reordering when databound to an ObservableCollection is all fixed now. Sorry for the problems.

    Hope this helps,
    -mark

    Program Manager
    Microsoft
    This post is provided "as-is"

    Thursday, May 3, 2012 12:59 AM
  • Is the issue of "reordering when databound to an ObservableCollection" all fixed? I am still seeing the same problem even when I set the binding as TwoWay.


    abhi

    Friday, July 6, 2012 5:46 PM