天天看點

【WP開發】讀寫剪貼闆

在WP 8.1中隻有Silverlight App支援操作剪貼闆的API,Runtime App并不支援。不過,在WP 10中也引入了可以操作剪貼闆的API。

順便說點題外話,有人會說,我8.1的開發還沒學了,Win10又來了,那我怎麼學得過來?放心,學得過來的D,因為隻要你對有WPF的基礎,再加上對RT App的學習就足夠應付Win 10上的app開發了。實際上,面向10的API都是在8.1的基礎上增加一點新的API而已,你不需要學習新的知識就可以直接玩10的開發了。

而且,你在10上依然可以繼續使用8.1的API。當然我指的是RuntimeApp,Silverlight的API有可能将來不用。雖然RT API使用起來看着和以往的.net類庫沒什麼差別,而實際上RT庫是基于COM的形式存在的,如果你足夠細心的話,通過在RT應用發生異常的時候,你都會看到來自COM的HRESULT值,在調用試的時候,你也能看到許多RT庫的類型顯示為COM對象。這是很有力的證據。

是以我大膽估計,RT庫就是為了優化性能而出現的,随同新的編譯器和.net 4.6的釋出,.net的性能會有更可觀的優化,這是肯定的事情。而對于Win 10,微軟也确實在努力優化,盡管現在是預覽版,問題肯定會多一些,但我使用Build 10041後,确實感覺到反應速度快了很多,因為我的筆記本配置不算很高,對性能是有一點兒敏感的。

好了,屁話說得太多了,為了避免大家向我扔石頭(如果你要扔的話,建議你扔瑪瑙),下面我再簡單說說“通用應用程式項目”(UAP),耍W10開發必須了解這個。

通過架構是在面向8.1(VS UD2)的時候出現,在這個通用應用中是分為三個項目的,相信大家有所了解。

1、面向Windows Phone的應用。

2、面向Windows的應用。

3、共享代碼。

平台共用的代碼通常會放到第三個項目中,不過這樣做有時候也覺得代碼管理起來不友善。

在面向10的項目中直接就合并成一個項目,而不再按平台分開,直接就統一到一個項目中,生成的應用程式你喜歡在手機上運作也行,在平闆上運作也行,沒有平闆在普通PC上耍也可以。

【WP開發】讀寫剪貼闆

在VS的“對象浏覽器”視窗中,你會發現有一個名為Universal App Platform的子集,它就是包含通用API的各個庫的集合,把多個平台可以共享的API都放到一起了,開發者就不必去管理共享代碼了。

當然你也可以繼續使用面向8.1的項目,這些項目模闆在“Store Apps”節點下面。

好了,有了上面的介紹,再進入咱們今天的正題就輕松了。

首先,參照上面截圖自己新項一個Windows 10的空白應用程式項目。

這裡我給出的示例比較簡單,就是複制和粘貼一張圖檔。還是和以前一樣,用XAML代碼來布局UI。

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal" VerticalAlignment="Top">
            <Image Name="imgSrc" Width="200" Height="200" />
            <Button Content="複制" Click="OnCopy"/>
        </StackPanel>
        <StackPanel Grid.Row="1" VerticalAlignment="Top" Orientation="Horizontal">
            <Image Name="imgDes" Width="200" Height="200"/>
            <Button Content="粘貼" Click="OnSet"/>
        </StackPanel>
    </Grid>      

然後在頁面加載後從項目目錄中讀出一個圖像檔案。

public MainPage()
        {
            this.InitializeComponent();
            this.Loaded += OnPageLoaded;
        }

        private async void OnPageLoaded(object sender, RoutedEventArgs e)
        {
            // 附加元件目中的圖檔
            StorageFile imgFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///1.jpg"));
            // 打開檔案流
            IRandomAccessStream stream = await imgFile.OpenReadAsync();
            // 顯示圖像
            BitmapImage bmp = new BitmapImage();
            bmp.DecodePixelWidth = 250;
            await bmp.SetSourceAsync(stream);
            this.imgSrc.Source = bmp;
            // 将流對象放入Tag屬性中暫存,稍後會用得上
            this.Tag = RandomAccessStreamReference.CreateFromStream(stream.CloneStream());
            stream.Dispose();
        }      

檔案流一般來說,用完就應該馬上關閉,不要借着别人的錢不還,但是,我們随後要把檔案流中的内容寫入剪貼闆,而檔案流被關閉後又無法操作了,于是,我調用CloneStream方法直接将流複制一份,這樣原來的檔案流可以關閉了,并且不影響後面的操作。并且指派給Tag屬性,随後在其他代碼中可以從Tag屬性取出流對象。

下面代碼将流中的資料寫入剪貼闆:

// 從Tag屬性中取出檔案流
            RandomAccessStreamReference stream = this.Tag as RandomAccessStreamReference;
            if (stream != null)
            {
                // 建立資料包裝
                DataPackage package = new DataPackage();
                // 放入内容
                package.SetBitmap(stream);
                // 将資料放入ClipBoard
                Clipboard.SetContent(package);
            }      

下面代碼從剪貼闆讀出資料,即“粘貼”:

// 從clip board中取出資料
            DataPackageView pack = Clipboard.GetContent();

            // 如果Count為0,表示剪貼闆中沒有可用的内容
            if (pack.AvailableFormats.Count == 0)
            {
                return;
            }
            else
            {
                foreach (string format in pack.AvailableFormats)
                {
                    System.Diagnostics.Debug.WriteLine(format);
                }
            }
            // 驗證格式是否正确
            if (pack.AvailableFormats.Where(s=>s == StandardDataFormats.Bitmap).Count() > 0)
            {

                // 讀出流
                RandomAccessStreamReference streamref = await pack.GetBitmapAsync();
                using (IRandomAccessStream streamIn = await streamref.OpenReadAsync())
                {
                    // 顯示圖檔
                    BitmapImage bmp = new BitmapImage();
                    bmp.DecodePixelWidth = 250;
                    await bmp.SetSourceAsync(streamIn);
                    this.imgDes.Source = bmp;
                }
                Clipboard.Clear(); //清除剪貼闆中的内容

            }      

完事了,例子就這麼簡單。結果如下圖。

【WP開發】讀寫剪貼闆

下面就給大家介紹一下知識點。

1、操作剪貼闆用的是Clipboard類(命名空間:Windows.ApplicationModel.DataTransfer),這個類是靜态的,也就是說它的成員也是靜态的,不用new就可以直接用。

2、要向剪貼闆寫入資料,就用SetContent方法,要從剪貼闆中讀出資料就用GetContent方法。

3、在寫入的時候,資料是通過DataPackage類來包裝的,而讀取時則是通過DataPackageView類來操作的。那麼,這兩個家夥有什麼差別呢?

【WP開發】讀寫剪貼闆

看到了吧,一個是SetXXXXX,一個是GetXXXXXX。是以,DataPackage是用于建立資料包的,而DataPackageView是用來讀資料包的。

4、操作也不難,寫什麼類型的資料就用什麼方法,如寫文本用SetText,讀文本用GetTextAsync。本示例是讀寫圖像,是以寫的時候調用SetBitmap方法,讀的時候調用GetBitmapAsync方法。注意,圖像的内容是用RandomAccessStreamReference類來封裝的流對象,通過靜态的CreateFromStream方法可以從現存的流建立新的RandomAccessStreamReference執行個體。

5、用DataPackageView方法檢索内容之前,應當通路AvailableFormats屬性,檢查一下剪貼闆上的内容是否可用,或者是空的。該屬性是一個字元串清單,如果清單中元素個數為0,說明剪貼闆中的資料無效。

6、Clipboard.Clear()方法清理剪貼闆中的内容。

随後,我把示例源代碼上傳,大家可以下載下傳下來玩玩。

下載下傳位址:https://files.cnblogs.com/files/tcjiaan/ClipboardApp.zip

===============================

這裡補充一下,現在Win10和VS2015都是預覽版,如果你害怕出現小問題,那你得謹慎使用,如果你像我這樣,不幹正經事,隻是體驗一下,可以在電腦上裝來耍耍。我比較窮,隻有一台筆記本,買不起新電腦,就花幾百塊錢買了一台國産的山寨平闆,8寸的螢幕是小了點,不過還是可以當電腦用的。是以我的筆記本用來開發實驗,山寨闆用來看看電子書,看看電影電視劇,和林妹妹聊聊天,還是可以用的。

要注意的是,裝Win10預覽版一定要裝最新釋出的Build 10041版本,否則面向Win 10通用應用的XAML設計器無法加載。一開始我也犯了這個錯誤,後來檢視一下清單中的XML檔案,才發現它要求的是Build 10030以上的版本,而大于這個版本的就隻有最近釋出的Build 10041了。

另外,有一件事,需要向各位讀者表示道歉的,有位細心的朋友發現《精通C# 5.0》中第54頁,定義的Book結構有一個屬性應該是ISBN,我弄錯為ISBM。這是我的疏忽,偏偏編輯在審稿時沒有注意,我在定稿時也沒看到。是以,向各位表示歉意。

繼續閱讀