zoukankan      html  css  js  c++  java
  • 【Win10应用开发】通过拖放来打开文件

    除了可以使用XXXFilePicker来浏览文件外,其实在UWP APP中,也可以向传统Windows窗口一样,通过拖放的方式来打开文件。

    处理过程和WPF的原理差不多,毕竟都是一脉相承,于是,在学习过程完全可以进行知识迁移。如果希望界面上某个可视化对象作为拖放的放置目标,请务必把它的AllowDrop属性设置为true,这是必须完成的,不然被拖动的内容无法放到该元素上。

    作为可视化对象的基类,UiElement类为拖放操作提供了支持。

    除了前面提到的AllowDrop属性,还包含以下事件:

    DragStarting:当开始拖放操作但未正式启动拖放时发生,在此事件中,你可以设置要传递的数据,如果后悔了,不想拖放了,在此事件中可以取消拖放操作。注意,此事件是针对当前对象而言的,即当前对象自身发起拖放操作时发生。要在当前对象上启动一个新的拖放操作,请调用当前对象的StartDragAsync方法。这些成员都是在UIElement上定义的,所以它的子类都会继承。

    DragEnter、DragOver和DragLeave:注意,这三个事件是被拖动的对象经过当前对象时发生的。当被拖动的对象进入当前对象的可视区域时会发生DragEnter事件;当被拖动的对象在当前对象上移动时会发生DragOver事件,只要被拖动对象还处理当前对象上方,那么你鼠标或手指只要动一下(坐标有变),DragOver事件也会发生。当被拖动的对象离开当前对象的可视区域时会发生DragLeave事件。整个过程在正常情况下应该为:Enter -> Over -> Leave。不正常情况下就难说了,比如有些质量特别好的鼠标,拖着拖着,光标就不见了。在DragEnter事件中,可以对拖过来的数据进行验证,如果不符合你的口味,可以考虑“退货”。

    Drop:当数据被拖到当前对象上,并且放开时发生。在该事件中就应该获取传递进来的数据。如果此时不获取就没机会了,“今生今世若不能结发,来世就是旁人家的了”。

    DropCompleted:放置操作完成后会发生该事件。你可以不处理这个事件。但你要注意,在这个事件中你是不能获取传递的数据的,前面发生的Drop事件是获取数据的最后机会,不要错过。

    下面给大家弄一个通过拖放来打开图片文件的示例。我就不搞太复杂了,免得有人说我装H。

    先看界面,重点是看开启拖放支持。

            <Border HorizontalAlignment="Center" VerticalAlignment="Center" Name="bd" Background="Blue" Padding="50,25" AllowDrop="True" DragEnter="OnDragenter" DragLeave="OnDragleave" Drop="OnDrop">
                <TextBlock Name="tb" FontSize="28" Foreground="White" Text="请把文件拖至此处"/>
            </Border>

    你要看的重点是:1、设置AllowDrop属性为True,记住,这一步必须,不然后面就不能把文件拖到这个Border上了;2、处理DragEnter事件,当文件被拖进来时验证一下被拖动的是不是文件;处理DragLeave事件,这个没什么事干,主要是在拖放离开Border后,恢复一下Border的“容貌”而已;处理Drop事件,当释放时获取文件,并显示图片。

    具体代码如下:

            private async void OnDragenter(object sender, DragEventArgs e)
            {
                // 获取Deferral是必须,稍后要用它来向系统报告操作完成
                var deferral = e.GetDeferral();
                DataPackageView dataview = e.DataView;
                // 验证数据类型,如果不是文件,就没戏了
                if (dataview.Contains(StandardDataFormats.StorageItems))
                {
                    // 取出被拖进来的文件列表
                    // 因为用户可能觉得好玩
                    // 一次性拖一大堆文件或目录进来
                    var items = await dataview.GetStorageItemsAsync();
                    if (items.Count > 0)
                    {
                        IStorageItem item = items[0];
                        // 这里只关心文件,如果拖的是目录,那就不玩了
                        if (item.IsOfType(StorageItemTypes.File))
                        {
                            // 设置一个有效的拖放操作,只要不是None就行
                            // 其他值都无所谓,主要区别是拖放时的光标显示不同
                            // 但后面我会把光标隐藏,以免影响视线
                            e.AcceptedOperation = DataPackageOperation.Link;
                            StorageFile file = (StorageFile)item;
                            // 得到文件预览图
                            var t = await file.GetScaledImageAsThumbnailAsync(Windows.Storage.FileProperties.ThumbnailMode.SingleItem, 150);
                            BitmapImage bmp = new BitmapImage();
                            bmp.DecodePixelWidth = 150;
                            bmp.SetSource(t);
                            // 设置拖动过程中显示的图标
                            e.DragUIOverride.SetContentFromBitmapImage(bmp);
                            // Caption属性表示在拖动时显示的提示文本
                            // 想看效果的话,就把下面这行代码取消注释
                            //e.DragUIOverride.Caption = file.Name;
                            // 不显示提示文本
                            // 所以,如果你想看上面的Caption值,请把
                            // IsCaptionVisible也改为true
                            e.DragUIOverride.IsCaptionVisible = false;
                            // 干脆连那个指针符号也隐藏了吧
                            e.DragUIOverride.IsGlyphVisible = false;
                        }
                        else
                        {
                            // 不是文件数据,就设置为None,无操作
                            e.AcceptedOperation = DataPackageOperation.None;
                        }
                    }
                }
                else
                {
                    e.AcceptedOperation = DataPackageOperation.None;
                }
                VisualStateManager.GoToState(this, "DragIn", false);
                // 告诉系统,我干完活了
                deferral.Complete();
            }
    
            private void OnDragleave(object sender, DragEventArgs e)
            {
                var d = e.GetDeferral();
                VisualStateManager.GoToState(this, "Generic", false);
                d.Complete();
            }
    private async void OnDrop(object sender, DragEventArgs e) { // 记得获取Deferral对象 var def = e.GetDeferral(); DataPackageView data = e.DataView; // 还是再验证一下吧,防止意外 if (data.Contains(StandardDataFormats.StorageItems)) { var storageItems = await data.GetStorageItemsAsync(); if (storageItems.Count > 0) { IStorageItem item = storageItems[0]; if (item.IsOfType(StorageItemTypes.File)) { StorageFile file = item as StorageFile; // 生成内存图像 using (var inStream = await file.OpenReadAsync()) { BitmapImage bmp = new BitmapImage(); bmp.DecodePixelWidth = 300; bmp.SetSource(inStream); img.Source = bmp; //显示图像 } } } } VisualStateManager.GoToState(this, "Generic", false); // 报告操作系统,处理完成 def.Complete(); }

    代码虽然比较long,但其实没什么,因为DragEnter和Drop事件的代码相近,但,DragEnter事件重点是验证数据,而Drop事件代码重点是获取数据。在该事件中你必须获取数据,否则Drop完之后,整个拖放操作已经完成,你不再有机会获取了。

    这里我必须说明一个非常严重的问题,本来不是很严重的,就是某些人粗心大意,倒弄出问题了。

    不少人在使用拖放中出现:应用程序运行后,第一次拖放操作可以顺利完成。但之后就不能拖放了。于是就反馈说有Bug。Bug你个头啊,为什么人家其他程序又能正常使用?

    你仔细看我的代码,在处理事件时,要先调用GetDeferral方法获取一个对象,在代码完成之后,调用这个对象的Complete方法,告知系统操作完成。这个Deferral我以前说过,Runtime App中常出现的,它大概是一个代理对象,来延缓某些线程的操作,直到Complete方法调用才释放。为什么说是代理对象,因为Runtime API类似于COM组件,实际上它是本地代码,只是为了和.net的风格统一,就封装为类似托管API的形式。

                var d = e.GetDeferral();
                ……
                d.Complete();

    记好了,以后遇到问题别瞎胡扯,多从自己身上找问题。毛主席常教导我们,多想出智慧,多做自我批评。

    运行应用程序,然后打开文件管理器,随便找个图像文件拖到窗口上的Border对象上,就可以打开文件了。

    得到文件后,可以显示图片了。

    好啦,快要刮台风了,所以牛逼就不多吹了,今天就吹到这里吧。

    示例代码下载:http://files.cnblogs.com/files/tcjiaan/dragOpenFileSmp.zip

  • 相关阅读:
    sqlite学习笔记9:C语言中使用sqlite之插入数据
    基于对话框的应用程序,点击button打开一个网页
    数组溢界地址的正确使用: 即 int a[6] 中的 a[-1] 和 a[6] 正确使用
    BeagleBone硬件概览Ethernet端口板载LEDc重置按钮等介绍
    ARP缓存记录种类动态条目和静态条目
    ArduinoYun的电源插座
    Xamarin开发Anroid应用介绍
    学习NGUI前的准备NGUI的相关信息
    Xamarin Android开发实战(上册)大学霸内部资料
    NGUI全面实践教程(大学霸内部资料)
  • 原文地址:https://www.cnblogs.com/tcjiaan/p/4737271.html
Copyright © 2011-2022 走看看