开发者

Drop Item into Specific Index in ListView in WPF C#

I have a list of files in a ListView开发者_Go百科 in WPF. Users can drag files onto the list view, and right now they are just appended to the end of the list. Is it possible to insert the file into the ListView right where the user dropped it?


WPF isn't really designed to be used that way. While you can brute force add ListViewItem's directly to the ListView, the way it's really supposed to work is that you have a collection of some kind (ObservableCollection<FileInfo> would work well) and bind the ListView's ItemsSource property to that collection.

Then the answer is simple. Instead of the Add method, you use the Insert method of the collection which takes an index.

As for finding which ListViewItem the mouse event occurred over, you could use the VisualTreeHelper.HitTest method.


From my point of view it is little tricky when I used the templated item. I have fight with it little bit. I am sharing my usecase which works with DraggableListBox. But I suppose the same solution works with ListBox control.

As the first I created the dependency object extension which is able to provide me ListItem element:

public static class WpfDomHelper
{
    public static T FindParent<T>(this DependencyObject child) where T : DependencyObject
    {

        DependencyObject parentObject = VisualTreeHelper.GetParent(child);

        if (parentObject == null) return null;

        T parent = parentObject as T;
        if (parent != null)
            return parent;
        else
            return FindParent<T>(parentObject);
    }
}

Then I implemented Drop logic which inserts(adds) item according specific Drop Y position of destination ListBoxItems:

    private void Grid_Drop(object sender, DragEventArgs e)
    {
        int dropIndex = -1; // default position directong to add() call

        // checking drop destination position
        Point pt = e.GetPosition((UIElement)sender);
        HitTestResult result = VisualTreeHelper.HitTest(this, pt);
        if (result != null && result.VisualHit != null)
        {
            // checking the object behin the drop position (Item type depend)
            var theOne = result.VisualHit.FindParent<Microsoft.TeamFoundation.Controls.WPF.DraggableListBoxItem>();

            // identifiing the position according bound view model (context of item)
            if (theOne != null)
            {
                //identifing the position of drop within the item
                var itemCenterPosY = theOne.ActualHeight / 2;
                var dropPosInItemPos = e.GetPosition(theOne); 

                // geting the index
                var itemIndex = tasksListBox.Items.IndexOf(theOne.Content);                    

                // decission if insert before or below
                if (dropPosInItemPos.Y > itemCenterPosY)
                {  // when drag is gropped in second half the item is inserted bellow
                    itemIndex = itemIndex + 1; 
                }
                dropIndex = itemIndex;
            }
        }

        .... here create the item .....

        if (dropIndex < 0)
             ViewModel.Items.Add(item);
        else
             ViewModel.Items.Insert(dropIndex, item);

        e.Handled = true;

    }

So this solution works with my template DraggableListBoxView, I suppose the same solution must work with standard ListBoxView. Good Luck


You can do this. It takes a bit of work, but it can be done. There are a couple demos out there, here is one on CodeProject. This particular one is by the wpf master known as Josh Smith. It's probably not exactly what you are looking for, but it should be pretty darn close.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜