Windows 10 UWP 10 of N: Drag and Drop

Windows 10 UWP 10 of N: Drag and Drop


今天来介绍个Windows APP重大的功能~就是拖拉!现在很多设备都是触控(Touch)为操控而直觉的手制(Gesture) 渐渐地变得越来越重要!

在Windows 8.1也是有支持拖拉但...只限定在App之中!而在Windows 10 的APP已经像是Win32的传统应用程序进行拖拉。

请看以下图片示范

image_thumb1

先建立三个区块并放入ListView(使用Red Green Blue为区分三大区块!)

image_thumb4

接者示范拖曳图片进去APP的最左边的ListView(Red)可以看到在拖曳进去APP的时候会显示Copy的小Popup!

image_thumb7

但拖曳到中间(Green)以及右边(Blue)的ListView就无法丢入图片的处理!

image_thumb10

左边的图片拖曳之后丢下(Drop)所做的简单UI。

image_thumb13image_thumb18

当第一张图片拖入中间的ListView时候(还未丢下的行为)在左图呈现,而右边的图片则是将第二张图片拖曳并放入到最右边的ListView的呈现画面。

那这么方便的功能请参考以下的Code

    x:
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:UWP_Sample1.View"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:model="using:UWP_Sample1.Model"
    DataContext="{Binding Source={StaticResource DragDropPageVM}}"
    mc:Ignorable="d">

    
        
            
                
                
                
            
        
    

    
        
            
            
            
        
        
        
        
    


在22行可以看到只放入三个Listview为拖拉的主要接收Control!而这三个Listview都必须要设定

AllowDrop、CanDragItems为True。AllowDrop就如同字面意思依样是否允许被丢下(Drop)、而CanDragItems就是是否能够拖曳List内的Item。

目前设定在第一个的ListView的SelectionMode为Extended就是可以被多选的状况。然后我定了三个ListView的ItemTemplate在Page的Resource内并使用x:Bind进行事件的Binding;DragOver以及Drop的事件分别处理的是拖曳到该Control所触发的和丢下所触发的事件!

接者到ViewModel的各个事件来说明详细的Code撰写。

        {
            if (sender is ListView)
            {
                switch ((sender as ListView).Tag.ToString())
                {
                    case "Col0Lv":
                        if (e.DataView.Contains(StandardDataFormats.StorageItems))
                        {
                            var isImages = false;
                            foreach (StorageFile item in await e.DataView.GetStorageItemsAsync())
                            {
                                if (item.FileType.ToLower() == ".jpg" || item.FileType.ToLower() == ".jpeg" || item.FileType.ToLower() == ".gif" || item.FileType.ToLower() == ".png")
                                    isImages = true;
                                else
                                    isImages = false;
                            }
                            if (isImages)
                                e.AcceptedOperation = DataPackageOperation.Copy;
                            else
                                e.AcceptedOperation = DataPackageOperation.None;
                        }
                        break;
                    case "Col1Lv":
                    case "Col2Lv":
                        if (e.DataView.Contains(StandardDataFormats.Text))
                            e.AcceptedOperation = DataPackageOperation.Move;
                        break;
                }
            }
        }




DragOver就是拖曳对象到该Control的时候触发的事件,我只有设定在listview的Tag是col0lv的时候并且DataView是包含StorageItem就可以进行Operation。这边需要注意的事是StorageItems是可以为任何对象所以在如果要做更加深入的拖曳进APP的Item判断可能就得要确认附文件名了!

    {
        //
        // Summary:
        //     No action. Typically used when the DataPackage object requires delayed rendering.
        None = 0,
        //
        // Summary:
        //     Copies the content to the target destination.
        Copy = 1,
        //
        // Summary:
        //     Copies the content to the target destination and deletes the original.
        Move = 2,
        //
        // Summary:
        //     Creates a link for the data.
        Link = 4
    }




DataOperation目前所支持的动作如上。

接者来做Drop的事件处理

        {
            if (sender is ListView)
            {
                switch ((sender as ListView).Tag.ToString())
                {
                    case "Col0Lv":
                        if (e.DataView.Contains(StandardDataFormats.StorageItems))
                        {
                            var storageItems = await e.DataView.GetStorageItemsAsync();
                            foreach (StorageFile item in storageItems)
                            {
                                var bImg = new BitmapImage();
                                await bImg.SetSourceAsync(await item.OpenReadAsync());
                                _SampleCol0Collection.Add(new SampleModel()
                                {
                                    Title = item.DisplayName,
                                    SubTitle = item.ContentType,
                                    ItemImageSource = bImg
                                });
                            }
                        }
                        break;
                    case "Col1Lv":
                        if (e.DataView.Contains(StandardDataFormats.Text))
                        {
                            var titles = await e.DataView.GetTextAsync();
                            var itemsToMove = titles.Split(',');
                            foreach (var moveItemTitle in titles.Split(','))
                            {
                                var tempItem = _SampleCol0Collection.First(i => i.Title == moveItemTitle);
                                _SampleCol1Collection.Add(tempItem);
                                _SampleCol0Collection.Remove(tempItem);
                            }
                        }
                        break;
                    case "Col2Lv":
                        if (e.DataView.Contains(StandardDataFormats.Text))
                        {
                            var titles = await e.DataView.GetTextAsync();
                            var itemsToMove = titles.Split(',');
                            foreach (var moveItemTitle in titles.Split(','))
                            {
                                var tempItem = _SampleCol0Collection.First(i => i.Title == moveItemTitle);
                                _SampleCol2Collection.Add(tempItem);
                                _SampleCol0Collection.Remove(tempItem);
                            }
                        }
                        break;
                }
            }
        }




这边要注意Col0Lv的处理比较简单!就是将拖曳进该控件的对象解析成BitmapImage并再放入SampleModel的ImageSource。

而Col1Lv以及Col2Lv需要特别注意!解析文字的原因是因为在DragItemOver的事件来决定的!

        {
            if (sender is ListView)
            {
                var items = string.Join(",", e.Items.Cast().Select(i => i.Title));
                e.Data.SetText(items);
                e.Data.RequestedOperation = DataPackageOperation.Move;
            }
        }




在Col0Lv的XAML我们有x:Bind DragItemsStarting事件,这个事件就是在Col0Lv的Item开始被拖曳的时候将该Title设定为传送的ID代码!( 这边最好是使用GUID来避免错误的拖曳数据,由于个人懒惰所以使用Title[文件名]作为识别的GUID )这样就可以组合成GUID的列表来作为Col0Lv丢Item给Col1Lv和Col2Lv的依据了!所以在Col1Lv和Col2Lv的Drop事件就是拆解字符串并将Col0Lv的Item转送到个别的Item中。

最后ViewModel完整的Code如下

    {
        private ObservableCollection _SampleCol0Collection;
        public ObservableCollection SampleCol0Collection
        {
            get { return _SampleCol0Collection; }
        }

        private ObservableCollection _SampleCol1Collection;
        public ObservableCollection SampleCol1Collection
        {
            get { return _SampleCol1Collection; }
        }

        private ObservableCollection _SampleCol2Collection;
        public ObservableCollection SampleCol2Collection
        {
            get { return _SampleCol2Collection; }
        }

        public DragAndDropPageViewModel()
        {
            _SampleCol0Collection = new ObservableCollection();
            _SampleCol1Collection = new ObservableCollection();
            _SampleCol2Collection = new ObservableCollection();
        }

        public void ListViewBase_DragOver(object sender, DragEventArgs e)
        {
            if (sender is ListView)
            {
                switch ((sender as ListView).Tag.ToString())
                {
                    case "Col0Lv":
                        if (e.DataView.Contains(StandardDataFormats.StorageItems))
                        {
                            var isImages = false;
                            foreach (StorageFile item in await e.DataView.GetStorageItemsAsync())
                            {
                                if (item.FileType.ToLower() == ".jpg" || item.FileType.ToLower() == ".jpeg" || item.FileType.ToLower() == ".gif" || item.FileType.ToLower() == ".png")
                                    isImages = true;
                                else
                                    isImages = false;
                            }
                            if (isImages)
                                e.AcceptedOperation = DataPackageOperation.Copy;
                            else
                                e.AcceptedOperation = DataPackageOperation.None;
                        }
                        break;
                    case "Col1Lv":
                    case "Col2Lv":
                        if (e.DataView.Contains(StandardDataFormats.Text))
                            e.AcceptedOperation = DataPackageOperation.Move;
                        break;
                }
            }
        }

        public async void ListViewBase_Drop(object sender, DragEventArgs e)
        {
            if (sender is ListView)
            {
                switch ((sender as ListView).Tag.ToString())
                {
                    case "Col0Lv":
                        if (e.DataView.Contains(StandardDataFormats.StorageItems))
                        {
                            var storageItems = await e.DataView.GetStorageItemsAsync();
                            foreach (StorageFile item in storageItems)
                            {
                                var bImg = new BitmapImage();
                                await bImg.SetSourceAsync(await item.OpenReadAsync());
                                _SampleCol0Collection.Add(new SampleModel()
                                {
                                    Title = item.DisplayName,
                                    SubTitle = item.ContentType,
                                    ItemImageSource = bImg
                                });
                            }
                        }
                        break;
                    case "Col1Lv":
                        if (e.DataView.Contains(StandardDataFormats.Text))
                        {
                            var titles = await e.DataView.GetTextAsync();
                            var itemsToMove = titles.Split(',');
                            foreach (var moveItemTitle in titles.Split(','))
                            {
                                var tempItem = _SampleCol0Collection.First(i => i.Title == moveItemTitle);
                                _SampleCol1Collection.Add(tempItem);
                                _SampleCol0Collection.Remove(tempItem);
                            }
                        }
                        break;
                    case "Col2Lv":
                        if (e.DataView.Contains(StandardDataFormats.Text))
                        {
                            var titles = await e.DataView.GetTextAsync();
                            var itemsToMove = titles.Split(',');
                            foreach (var moveItemTitle in titles.Split(','))
                            {
                                var tempItem = _SampleCol0Collection.First(i => i.Title == moveItemTitle);
                                _SampleCol2Collection.Add(tempItem);
                                _SampleCol0Collection.Remove(tempItem);
                            }
                        }
                        break;
                }
            }
        }

        public void ListViewBase_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
        {
            if (sender is ListView)
            {
                var items = string.Join(",", e.Items.Cast().Select(i => i.Title));
                e.Data.SetText(items);
                e.Data.RequestedOperation = DataPackageOperation.Move;
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyChange([CallerMemberName]string propertyName = "")
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }


*以上Code以及说明都有可能随着Windows 10 的版本以及Visual Studio 2015版本有所调整!*

参考数据 MSDN

下次再分享Windows 10 的新技术拉~