Windows应用商店的应用程序拖拽列表视图之间下降 [英] Windows Store App drag and drop between ListViews

查看:136
本文介绍了Windows应用商店的应用程序拖拽列表视图之间下降的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我建立一个Windows Store应用/通用应用程序针对Windows 8.1和Windows 10,我希望能够拖动和列表视图之间的掉落物品,并能够在ListView中一个特定点的项目定位。我遇到的主要问题是,我不能找到一个很好的方式,以确定该项目已下降的列表索引。

I am building a Windows Store App / Universal App targeting Windows 8.1 and Windows 10 and I would like to be able to drag and drop items between ListViews and be able to position the item in a specific spot in the ListView. The main problem I'm having is that I can't find a good way to determine the list index of where the item was dropped.

我发现了一个样本( XAML ListView的重新排序),但一个重要的区别是,在我的列表中的项目有不同高度所以简单计算此示例项目使用推断该索引将不会为我工作。

I found a sample (XAML ListView reorder) but an important difference is that the items in my list have variable heights so the simple calculation this sample project uses to infer the index won't work for me.

我能够得到x,其中在ListView中的项目是下降的y位置,但我使用这个位置要弄清楚指数遇到了麻烦。我发现提到的使用ListView.GetItemAt(X,Y​​)或ListView.HitTest(X,Y​​)的人,但其他人发现,似乎这些方法不能在Windows应用程序的通用存在。我已经使用VisualTreeHelper.FindElementsInHostCoordinates()也试过,但我要么不使用它正确或者说我不理解它的目的,因为我无法得到它的返回结果。

I am able to get the x,y position of where within the ListView the item was dropped, but I'm having trouble using that position to figure out the index. I've found mentions of people using ListView.GetItemAt(x, y) or ListView.HitTest(x, y) but as other have found, those methods don't seem to exist in Windows Universal apps. I've also tried using VisualTreeHelper.FindElementsInHostCoordinates() but I'm either not using it properly or I'm not understanding its purpose because I can't get it to return results.

下面是我已经尝试了一些例如code:

Here is some example code that I've tried:

private void ListView_OnDrop(object sender, DragEventArgs e)
{
    var targetListView = (ListView)sender;

    var positionRelativeToTarget = e.GetPosition(targetListView);

    var rect = new Rect(positionRelativeToTarget, new Size(10, 15));
    var elements = VisualTreeHelper.FindElementsInHostCoordinates(rect, targetListView);

    // Trying to get the index in the list where the item was dropped
    // 'elements' is always empty
}

有关参考,我使用C#,XAML,和Visual Studio 2013。

For reference, I'm using C#, XAML, and Visual Studio 2013.

谢谢!

推荐答案

我找到了一个解决方案,我的目的不够好。从本质上讲是我落得这样做处理上ListView和列表项都落事件,因为它很容易,如果降一个列表项发生弄清楚索引。我仍然不得不处理的ListView中降得的虽然项目时之间滴入

I found a solution that is good enough for my purposes. Essentially what I ended up doing was handling the drop event on both the ListView and the list item because it's easy to figure out the index if the drop happens on a list item. I still had to handle the drop on the ListView too though for when an item is dropped in between.

下面是code我结束了:

Here is the code I ended up with:

MyView.xaml

<UserControl.Resources>    
    <DataTemplate x:Key="MyItemTemplate">
        <local:MyControl AllowDrop="True" Drop="ListItem_OnDrop" />
    </DataTemplate>
</UserControl.Resources>

<Grid>
    <ListView ItemTemplate="{StaticResource MyItemTemplate}"
              CanDragItems="True" AllowDrop="True"
              DragItemsStarting="ListView_OnDragItemsStarting"
              DragOver="ListView_OnDragOver"
              DragLeave="ListView_OnDragLeave"
              Drop="ListView_OnDrop" />
</Grid>

MyView.xaml.cs

public sealed partial class MyView
{
    private readonly SolidColorBrush listViewDragOverBackgroundBrush = new SolidColorBrush(Color.FromArgb(255, 247, 247, 247));

    public MyView()
    {
        InitializeComponent();
    }

    private IMyViewModel ViewModel
    {
        get { return DataContext as IMyViewModel; }
    }

    private void ListView_OnDragItemsStarting(object sender, DragItemsStartingEventArgs e)
    {
        e.Data.Properties.Add("dataItem", e.Items[0] as IMyItemViewModel);
    }

    private void ListView_OnDragOver(object sender, DragEventArgs e)
    {
        var dropTarget = sender as ListView;
        if (dropTarget == null)
        {
            return;
        }

        dropTarget.Background = listViewDragOverBackgroundBrush;
    }

    private void ListView_OnDragLeave(object sender, DragEventArgs e)
    {
        var dropTarget = sender as ListView;
        if (dropTarget == null)
        {
            return;
        }

        dropTarget.Background = null;
    }

    private void ListView_OnDrop(object sender, DragEventArgs e)
    {
        var draggedItem = e.Data.Properties["dataItem"] as IMyItemViewModel;
        var targetListView = sender as ListView;

        if (targetListView == null || draggedItem == null)
        {
            return;
        }

        targetListView.Background = null;

        var droppedPosition = e.GetPosition(targetListView);
        var itemsSource = targetListView.ItemsSource as IList;
        const double extraHeightThatImNotSureWhereItCameFrom = 8d;
        var highWaterMark = 3d;  // This list starts with 3px of padding
        var dropIndex = 0;
        var foundDropLocation = false;

        for (int i = 0; i < itemsSource.Count && !foundDropLocation; i++)
        {
            var itemContainer = (ListViewItem)targetListView.ContainerFromIndex(i);

            highWaterMark = highWaterMark + itemContainer.ActualHeight - extraHeightThatImNotSureWhereItCameFrom;

            if (droppedPosition.Y <= highWaterMark)
            {
                dropIndex = i;
                foundDropLocation = true;
            }
        }

        if (foundDropLocation)
        {
            // Handle the drag/drop at a specific location
            // DropPosition is an enumeration I made that has Before & After
            ViewModel.CompleteDragDrop(draggedItem, DropPosition.Before, dropIndex);
        }
        else
        {
            // Add to the end of the list. Also works for an empty list.
            ViewModel.CompleteEvidenceDragDrop(draggedItem, DropPosition.After, itemsSource.Count - 1);
        }
    }

    private void ListItem_OnDrop(object sender, DragEventArgs e)
    {
        e.Handled = true;

        var draggedItem = e.Data.Properties["dataItem"] as IMyItemViewModel;
        var dropTarget = sender as MyControl;

        if (dropTarget == null || draggedItem == null)
        {
            return;
        }

        var parentList = dropTarget.Closest<ListView>();
        var dropPosition = dropTarget.GetDropPosition(e);

        parentList.Background = null;

        ViewModel.CompleteDragDrop(draggedItem, dropPosition, dropTarget.DataContext as IMyItemViewModel);
    }
}

ExtensionMethods

public static class ExtensionMethods
{
    public static T Closest<T>(this DependencyObject obj) where T : DependencyObject
    {
        if (obj == null)
        {
            return null;
        }

        while (true)
        {
            var parent = VisualTreeHelper.GetParent(obj);

            if (parent == null)
            {
                return null;
            }

            if (parent.GetType() == typeof(T))
            {
                return (T)parent;
            }

            obj = parent;
        }
    }

    public static DropPosition GetDropPosition(this FrameworkElement dropTarget, DragEventArgs e)
    {
        var positionRelativeToTarget = e.GetPosition(dropTarget);

        var dropBefore = positionRelativeToTarget.Y < (dropTarget.ActualHeight / 2);

        return dropBefore ? DropPosition.Before : DropPosition.After;
    }
}

这篇关于Windows应用商店的应用程序拖拽列表视图之间下降的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆