Skip to content

Commit

Permalink
完成 Hands-on-Lab 3 的內容
Browse files Browse the repository at this point in the history
  • Loading branch information
ericsk committed Aug 2, 2015
1 parent 0712919 commit 18cbe78
Show file tree
Hide file tree
Showing 23 changed files with 664 additions and 1 deletion.
172 changes: 172 additions & 0 deletions HOL/HOL3_Local_Image_Viewer.md
@@ -0,0 +1,172 @@
# Lab 3 - 讀取用戶的圖片瀏覽器

預估時間: **30 分鐘**

## Lab 說明

透過這份 Lab 瞭解如何存取 App 套件內的檔案,以及使用 FileOpenPicker 讓用戶選擇要存取的檔案。

## 1. 開啟 Visual Studio 20015 並建立新專案

開啟 Visual Studio 2015,在啟始頁左側選擇_「新增專案...」_或是從上方功能表列選取_「檔案」_ » _「新增」_ » _「專案...」_

![建立新專案](images/1-create-new-project.png)

在新增專案的對話視窗中,在左側的範本中選擇 _「Visual C#」_ » _「Windows」_ » _「Windows Universal」_ ,然後選擇_「Blank App (Windows Universal)」_,最後再下方的名稱處輸入專案名稱,這裡使用 _LocalImageViewer_,完成後按下_確定_按鈕開始建立專案。

![建立空白 UWP App 專案](images/3-create-new-project.png)

## 2. 設定操作介面

打開 **MainPage.xaml** 檔案,將 XAML 檔案內容修改為:

```xml
<Page
x:Class="LocalImageViewer.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:LocalImageViewer"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="120" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<TextBlock Grid.Row="0" Text="圖片瀏覽器" VerticalAlignment="Center"
Style="{StaticResource HeaderTextBlockStyle}" Margin="20" />

<ScrollViewer Grid.Row="1">
<StackPanel Margin="20, 0">
<Button x:Name="OpenFileButton" Content="開啟檔案" Click="OpenFileButtonClicked" />

<Image x:Name="ImageTarget" Stretch="UniformToFill" Margin="0,20" />
</StackPanel>
</ScrollViewer>

</Grid>
</Page>
```

操作介面很簡單,就是一個按鈕讓使用者選擇要用什麼檔案來顯示,而 ```<Image />``` 元件就是用來顯示圖片使用的。

## 3. 將 Placeholder 圖片放入專案內

下載 [Placeholder 圖片](images/placeholder.png),然後放在專案內的 **Assets** 目錄下,記得在屬性設定中,將**複製到輸出目錄**設定成_永遠複製_**建置動作**設成_內容_

![加入 placeholer 圖片](images/3-add-placeholder.png)

## 4. 在程式啟動時套上 Placeholder 圖片

打開 **MainPage.xaml.cs** 檔案,然後在建構式加入 ```Loaded``` 事件,並且在這事件的處理函式中讀取 placeholder 圖片然後放在 ```<Image />``` 元件上。

```csharp
public MainPage()
{
this.InitializeComponent();

Loaded += MainPage_Loaded;
}

private async void MainPage_Loaded(object sender, RoutedEventArgs e)
{
var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(@"ms-appx:///Assets/placeholder.png"));
using (var stream = await file.OpenAsync(FileAccessMode.Read))
{
var bitmap = new BitmapImage();
await bitmap.SetSourceAsync(stream);
ImageTarget.Source = bitmap;
}
}
```

在這裡我們可以看到如何使用 ```ms-appx:///``` 的 URI 形式來存取在 app 套件中的檔案。

## 5. 讓使用者選擇檔案

同樣地,我們在 **MainPage.xaml.cs** 檔案中加入畫面中按鈕的處理函式,並且在裡面使用 ```FileOpenPicker``` API 來讓使用者自行選擇圖片(副檔名為 jpg 的圖片)來顯示。

```csharp
private async void OpenFileButtonClicked(object sender, RoutedEventArgs args)
{
FileOpenPicker picker = new FileOpenPicker();
picker.ViewMode = PickerViewMode.Thumbnail;
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;

picker.FileTypeFilter.Add(".jpg");

StorageFile file = await picker.PickSingleFileAsync();
if (file != null)
{
using (var stream = await file.OpenAsync(FileAccessMode.Read))
{
var bitmap = new BitmapImage();
await bitmap.SetSourceAsync(stream);
ImageTarget.Source = bitmap;
}
}
}
```

這裡我們使用 ```FileOpenPicker``` 物件,讓它以縮圖方式呈現檔案、建議從用戶的圖片目錄開始,然後在 ```FileTypeFilter``` 加上 ```.jpg``` 的描述,讓選擇檔案的對話盒只會顯示副檔名是 .jpg 結尾的檔案,取得檔案後就可以打開套用在 ```<Image />``` 元件上。

所以完整的 ```MainPage.xaml.cs``` 檔案會像是這樣:

```csharp
using System;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;

namespace LocalImageViewer
{
/// <summary>
/// 可以在本身使用或巡覽至框架內的空白頁面。
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();

Loaded += MainPage_Loaded;
}

private async void MainPage_Loaded(object sender, RoutedEventArgs e)
{
var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(@"ms-appx:///Assets/placeholder.png"));
using (var stream = await file.OpenAsync(FileAccessMode.Read))
{
var bitmap = new BitmapImage();
await bitmap.SetSourceAsync(stream);
ImageTarget.Source = bitmap;
}
}

private async void OpenFileButtonClicked(object sender, RoutedEventArgs args)
{
FileOpenPicker picker = new FileOpenPicker();
picker.ViewMode = PickerViewMode.Thumbnail;
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;

picker.FileTypeFilter.Add(".jpg");

StorageFile file = await picker.PickSingleFileAsync();
if (file != null)
{
using (var stream = await file.OpenAsync(FileAccessMode.Read))
{
var bitmap = new BitmapImage();
await bitmap.SetSourceAsync(stream);
ImageTarget.Source = bitmap;
}
}
}
}
}
```
Binary file added HOL/images/3-add-placeholder.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added HOL/images/3-create-new-project.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added HOL/images/placeholder.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 40 additions & 0 deletions Projects/HOL3-LocalImageViewer/LocalImageViewer.sln
@@ -0,0 +1,40 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LocalImageViewer", "LocalImageViewer\LocalImageViewer.csproj", "{68B32EDA-9936-49C5-806A-9E71FC4FEDFD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM = Debug|ARM
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|ARM = Release|ARM
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{68B32EDA-9936-49C5-806A-9E71FC4FEDFD}.Debug|ARM.ActiveCfg = Debug|ARM
{68B32EDA-9936-49C5-806A-9E71FC4FEDFD}.Debug|ARM.Build.0 = Debug|ARM
{68B32EDA-9936-49C5-806A-9E71FC4FEDFD}.Debug|ARM.Deploy.0 = Debug|ARM
{68B32EDA-9936-49C5-806A-9E71FC4FEDFD}.Debug|x64.ActiveCfg = Debug|x64
{68B32EDA-9936-49C5-806A-9E71FC4FEDFD}.Debug|x64.Build.0 = Debug|x64
{68B32EDA-9936-49C5-806A-9E71FC4FEDFD}.Debug|x64.Deploy.0 = Debug|x64
{68B32EDA-9936-49C5-806A-9E71FC4FEDFD}.Debug|x86.ActiveCfg = Debug|x86
{68B32EDA-9936-49C5-806A-9E71FC4FEDFD}.Debug|x86.Build.0 = Debug|x86
{68B32EDA-9936-49C5-806A-9E71FC4FEDFD}.Debug|x86.Deploy.0 = Debug|x86
{68B32EDA-9936-49C5-806A-9E71FC4FEDFD}.Release|ARM.ActiveCfg = Release|ARM
{68B32EDA-9936-49C5-806A-9E71FC4FEDFD}.Release|ARM.Build.0 = Release|ARM
{68B32EDA-9936-49C5-806A-9E71FC4FEDFD}.Release|ARM.Deploy.0 = Release|ARM
{68B32EDA-9936-49C5-806A-9E71FC4FEDFD}.Release|x64.ActiveCfg = Release|x64
{68B32EDA-9936-49C5-806A-9E71FC4FEDFD}.Release|x64.Build.0 = Release|x64
{68B32EDA-9936-49C5-806A-9E71FC4FEDFD}.Release|x64.Deploy.0 = Release|x64
{68B32EDA-9936-49C5-806A-9E71FC4FEDFD}.Release|x86.ActiveCfg = Release|x86
{68B32EDA-9936-49C5-806A-9E71FC4FEDFD}.Release|x86.Build.0 = Release|x86
{68B32EDA-9936-49C5-806A-9E71FC4FEDFD}.Release|x86.Deploy.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
8 changes: 8 additions & 0 deletions Projects/HOL3-LocalImageViewer/LocalImageViewer/App.xaml
@@ -0,0 +1,8 @@
<Application
x:Class="LocalImageViewer.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:LocalImageViewer"
RequestedTheme="Light">

</Application>
95 changes: 95 additions & 0 deletions Projects/HOL3-LocalImageViewer/LocalImageViewer/App.xaml.cs
@@ -0,0 +1,95 @@
using System;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace LocalImageViewer
{
/// <summary>
/// 提供應用程式專屬行為以補充預設的應用程式類別。
/// </summary>
sealed partial class App : Application
{
/// <summary>
/// 初始化單一應用程式物件。這是第一行執行之撰寫程式碼,
/// 而且其邏輯相當於 main() 或 WinMain()。
/// </summary>
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
}

/// <summary>
/// 在應用程式由使用者正常啟動時叫用。當啟動應用
/// 將在例如啟動應用程式時使用以開啟特定檔案。
/// </summary>
/// <param name="e">關於啟動要求和處理序的詳細資料。</param>
protected override void OnLaunched(LaunchActivatedEventArgs e)
{

#if DEBUG
if (System.Diagnostics.Debugger.IsAttached)
{
this.DebugSettings.EnableFrameRateCounter = true;
}
#endif

Frame rootFrame = Window.Current.Content as Frame;

// 當視窗中已有內容時,不重複應用程式初始化,
// 只確定視窗是作用中
if (rootFrame == null)
{
// 建立框架做為巡覽內容,並巡覽至第一頁
rootFrame = new Frame();

rootFrame.NavigationFailed += OnNavigationFailed;

if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: 從之前暫停的應用程式載入狀態
}

// 將框架放在目前視窗中
Window.Current.Content = rootFrame;
}

if (rootFrame.Content == null)
{
// 在巡覽堆疊未還原時,巡覽至第一頁,
// 設定新的頁面,方式是透過傳遞必要資訊做為巡覽
// 參數
rootFrame.Navigate(typeof(MainPage), e.Arguments);
}
// 確定目前視窗是作用中
Window.Current.Activate();
}

/// <summary>
/// 在巡覽至某頁面失敗時叫用
/// </summary>
/// <param name="sender">導致巡覽失敗的框架</param>
/// <param name="e">有關巡覽失敗的詳細資料</param>
void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
{
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
}

/// <summary>
/// 在應用程式暫停執行時叫用。應用程式狀態會儲存起來,
/// 但不知道應用程式即將結束或繼續,而且仍將記憶體
/// 的內容保持不變。
/// </summary>
/// <param name="sender">暫停之要求的來源。</param>
/// <param name="e">有關暫停之要求的詳細資料。</param>
private void OnSuspending(object sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
//TODO: 儲存應用程式狀態,並停止任何背景活動
deferral.Complete();
}
}
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 18cbe78

Please sign in to comment.