티스토리 뷰

반응형

얼마전 개발 모임에서 FileOpenPicker 사용법이 Windows 8.1과 Windows Phone 8.1이 서로 달라서, 상당히 불편하다는 이야기를 듣게 되었다. 그래서 샘플작업을 진행하다가 그 부분을 동일하게 사용할 수 있는 방법이 있을까하고 찾아보니 적당한 내용이 있어서 심플하게 수정해 보았다.

 

1. 참고 포스트

Mike Taulty's Blog : 좋은 포스트를 많이 해주는 분이다.

Windows/Phone 8.1–Returning to the File Open Picker Abstraction

http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2014/05/28/windows-phone-8-1-returning-to-the-file-open-picker-abstraction.aspx

 

이 포스트에서는 PCL과 TaskCompletionSource를 이용해서 처리를 했는데, PCL을 사용하지 않는 분들을 위해 Shared 프로젝트에서 사용이 가능하도록 변경했다.

 

2. StorageHelper.cs

 

using System.Linq;
using System.Threading.Tasks;
using Windows.ApplicationModel.Activation;
using Windows.ApplicationModel.Core;
using Windows.Storage;
using Windows.Storage.Pickers;

 

namespace UniversalSample.Commons
{
    /// <summary>
    /// StorageHelper
    /// </summary>
    public class StorageHelper
    {
        private static StorageHelper _instance;

        /// <summary>
        /// Instance
        /// </summary>
        public static StorageHelper Instance
        {
            get { return _instance = _instance ?? new StorageHelper(); }
        }

#if WINDOWS_APP
        public async Task<StorageFile> PickSingleFileAsync(FileOpenPicker picker)
        {
            StorageFile file = await picker.PickSingleFileAsync();
            return file;
        }
#else
        //Windows Phone 8.1

        /// <summary>
        /// completionSource
        /// </summary>
        private TaskCompletionSource<StorageFile> completionSource;

 

        /// <summary>
        /// PickSingleFileAsync
        /// </summary>
        /// <param name="picker"></param>
        /// <returns></returns>
        public async Task<StorageFile> PickSingleFileAsync(FileOpenPicker picker)
        {
            //TaskCompletionSource 생성
            completionSource = new TaskCompletionSource<StorageFile>();

            //앱의 Activated 이벤트 연결
            CoreApplication.GetCurrentView().Activated += OnApplicationActivated;

            //PickSingleFileAndContinue 메소드 실행
            picker.PickSingleFileAndContinue();

            //TaskCompletionSource가 완료될 때까지 기다림, 결과는 StorageFile
            var file = await completionSource.Task;

            //file 리턴
            return file;
        }

 

        /// <summary>
        /// OnApplicationActivated
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void OnApplicationActivated(CoreApplicationView sender, IActivatedEventArgs args)
        {
            //Args확인
            var continueArgs = args as FileOpenPickerContinuationEventArgs;
           
            if (continueArgs != null && continueArgs.Files.Any())
            {
                //completionSource가 존재하면
                if (completionSource != null)
                {
                    //결과 세팅
                    completionSource.TrySetResult(continueArgs.Files.First());
                    //completionSource 삭제
                    completionSource = null;
                }

            }
            else
            {
                //선택한 파일이 존재하지 않으면
                if (completionSource != null)
                {
                    //취소 세팅
                    completionSource.TrySetCanceled();
                    completionSource = null;
                }

            }
            //이벤트 연결 해제
            CoreApplication.GetCurrentView().Activated -= OnApplicationActivated;
        }
#endif
    }
}

 

작업의 핵심 기능은 TaskCompletionSource을 이용해서 Task를 지연 시키는 것이다. PickSingleFileAsync가 호출되었을 때 하나의 Task를 생성하고 PickSingleFileAndContinue() 메소드를 호출 후 Task가 StorageFile을 반환할 때까지 무한정 기다리도록 한다. 그러면, 사용자가 파일을 선택하고, Activated 이벤트가 발생하면, 파일이 있는지 확인해 보고 completionSource에 결과를 세팅하거나, 취소를 세팅해서 Task를 완료 시킨다. Task가 완료되면 대기하고 있던 내용을 계속 진행하게 되는 것이다.

 

3. Using sample

 

        /// <summary>
        /// Open Image Command
        /// </summary>
        public RelayCommand OpenImageCommand
        {
            get { return _openImageCommand = _openImageCommand ?? new RelayCommand(async args =>
            {
                var openPicker = new FileOpenPicker();
                openPicker.ViewMode = PickerViewMode.Thumbnail;
                openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
                openPicker.FileTypeFilter.Add(".jpg");
                openPicker.FileTypeFilter.Add(".jpeg");
                openPicker.FileTypeFilter.Add(".png");
                TestText = "FileOpen Start";
                StorageFile file = await StorageHelper.Instance.PickSingleFileAsync(openPicker);
                if (file != null)
                {
                    var bitmapImage = new BitmapImage();
                    using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.Read))
                    {
                        // Set the image source to the selected bitmap
                        ImageProperties property = await file.Properties.GetImagePropertiesAsync();
                        bitmapImage.DecodePixelHeight = (int)property.Height;
                        bitmapImage.DecodePixelWidth = (int)property.Width;
                        await bitmapImage.SetSourceAsync(fileStream);
                    }
                    SelectedImageSource = bitmapImage;
                    TestText = "FileOpen End";
                }
            }); }
        }

 

뷰모델에서는 Windows 8.1인지, Windows Phone 8.1인지 상관하지 않고 위와 같이 사용하면 동일한 동작이 가능하다.

 

* Open Image button click

 

* FileOpenPicker 화면

 

* 선택한 이미지 출력

 

 

4. 파일 피커와 웹브로커를 위와 같은 방법으로 구현하면 쉽게 사용이 가능할 것이라 생각한다. 나중에 다른 내용들도 구현하게 되면 올리도록 하겠다.

 

전체 소스 

UniversalSample_20140618.zip

 

반응형

'UWP & Windows App > Beginner' 카테고리의 다른 글

shorten url - universal sample  (0) 2014.08.01
bitly서비스를 이용해서 url 짧게 변환 해보자  (0) 2014.07.30
Page navigation part2  (0) 2014.06.12
Page navigation part1  (0) 2014.05.19
Hello World Universal App  (0) 2014.05.10
댓글