posts - 455, comments - 9793, trackbacks - 594, articles - 0
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

公告

重新想象 Windows 8 Store Apps (28) - 选取器: CachedFileUpdater(缓存文件更新程序)

Posted on 2013-05-23 08:51 webabcd 阅读(...) 评论(...) 编辑 收藏

[源码下载]


重新想象 Windows 8 Store Apps (28) - 选取器: CachedFileUpdater(缓存文件更新程序)



作者:webabcd


介绍
重新想象 Windows 8 Store Apps 之 选取器

  • CachedFileUpdater - 缓存文件更新程序



示例
一、首先新建一个 Windows 应用商店项目,使其作为缓存文件更新程序

1、 打开一个文件,并关联到 CachedFileUpdater
CachedFileUpdaterProvider/MyOpenPicker.xaml

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

    <Grid Background="Transparent">
        <StackPanel Margin="120 0 0 0">

            <TextBlock Name="lblMsg" FontSize="14.667" />

            <Button Name="btnPickCachedFileLocal" Content="提供一个由 Local 更新的 CachedFile(由 CachedFileUpdater 更新 CachedFile)" Click="btnPickCachedFileLocal_Click_1" Margin="0 10 0 0" />

            <Button Name="btnPickCachedFileRemote" Content="提供一个由 Remote 更新的 CachedFile(由 app 更新 CachedFile)" Click="btnPickCachedFileRemote_Click_1" Margin="0 10 0 0" />

        </StackPanel>
    </Grid>
</Page>

CachedFileUpdaterProvider/MyOpenPicker.xaml.cs

/*
 * 打开一个文件,并关联到 CachedFileUpdater
 * 
 * 1、在 Package.appxmanifest 中新增一个“文件打开选取器”声明,并做相关配置
 * 2、在 App.xaml.cs 中 override void OnFileOpenPickerActivated(FileOpenPickerActivatedEventArgs args),如果 app 是由文件打开选取器激活的,则可以在此获取其相关信息
 */

using System;
using Windows.ApplicationModel.Activation;
using Windows.Storage;
using Windows.Storage.Pickers.Provider;
using Windows.Storage.Provider;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace CachedFileUpdaterProvider
{
    public sealed partial class MyOpenPicker : Page
    {
        private FileOpenPickerUI _fileOpenPickerUI;

        public MyOpenPicker()
        {
            this.InitializeComponent();
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            var args = (FileOpenPickerActivatedEventArgs)e.Parameter;
            _fileOpenPickerUI = args.FileOpenPickerUI;

            _fileOpenPickerUI.Title = "自定义文件打开选取器";
        }

        // 本 CachedFile 用于从 Local 更新
        private async void btnPickCachedFileLocal_Click_1(object sender, Windows.UI.Xaml.RoutedEventArgs e)
        {
            StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync(@"webabcdCachedFileUpdaterLocal.txt", CreationCollisionOption.ReplaceExisting);
            string textContent = "I am webabcd";

            await FileIO.WriteTextAsync(file, textContent);

            /*
             * 设置 CachedFile,即将文件关联到 CachedFileUpdater
             * SetUpdateInformation(IStorageFile file, string contentId, ReadActivationMode readMode, WriteActivationMode writeMode, CachedFileOptions options);
             *     file - 与 CachedFileUpdater 关联的文件
             *     contentId - 与 CachedFileUpdater 关联的文件标识
             */
            CachedFileUpdater.SetUpdateInformation(file, "cachedFileLocal", ReadActivationMode.BeforeAccess, WriteActivationMode.NotNeeded, CachedFileOptions.RequireUpdateOnAccess);

            lblMsg.Text = "选择的文件: " + file.Name;
            AddFileResult result = _fileOpenPickerUI.AddFile("myFile", file);
        }

        // 本 CachedFile 用于从 Remote 更新
        private async void btnPickCachedFileRemote_Click_1(object sender, Windows.UI.Xaml.RoutedEventArgs e)
        {
            StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync(@"webabcdCachedFileUpdaterRemote.txt", CreationCollisionOption.ReplaceExisting);
            string textContent = "I am webabcd";

            await FileIO.WriteTextAsync(file, textContent);

            /*
             * 设置 CachedFile,即将文件关联到 CachedFileUpdater
             * SetUpdateInformation(IStorageFile file, string contentId, ReadActivationMode readMode, WriteActivationMode writeMode, CachedFileOptions options);
             *     file - 与 CachedFileUpdater 关联的文件
             *     contentId - 与 CachedFileUpdater 关联的文件标识
             */
            CachedFileUpdater.SetUpdateInformation(file, "cachedFileRemote", ReadActivationMode.NotNeeded, WriteActivationMode.AfterWrite, CachedFileOptions.RequireUpdateOnAccess);

            lblMsg.Text = "选择的文件: " + file.Name;
            AddFileResult result = _fileOpenPickerUI.AddFile("myFile", file);
        }
    }
}


2、 开发自定义缓存文件更新程序
CachedFileUpdaterProvider/MyCachedFileUpdater.xaml

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

    <Grid Background="Transparent">
        <StackPanel Margin="120 0 0 0">

            <TextBlock Name="lblMsg" FontSize="14.667" />

            <Button Name="btnUpdate" Content="更新 CachedFile(由 CachedFileUpdater 更新 CachedFile)" Click="btnUpdate_Click_1" Margin="0 10 0 0" />

        </StackPanel>
    </Grid>
</Page>

CachedFileUpdaterProvider/MyCachedFileUpdater.xaml.cs

/*
 * 演示如何开发自定义缓存文件更新程序
 * 
 * 1、在 Package.appxmanifest 中新增一个“缓存文件更新程序”声明,并做相关配置
 * 2、在 App.xaml.cs 中 override void OnCachedFileUpdaterActivated(CachedFileUpdaterActivatedEventArgs args),如果 app 是由文件打开选取器激活的,则可以在此获取其相关信息
 * 
 * CachedFileUpdaterActivatedEventArgs - 通过“缓存文件更新程序”激活应用程序时的事件参数
 *     CachedFileUpdaterUI - 获取 CachedFileUpdaterUI 对象
 *     PreviousExecutionState, Kind, SplashScreen - 各种激活 app 的方式的事件参数基
 * 
 * CachedFileUpdaterUI - 缓存文件更新程序的帮助类
 *     Title - 将在“缓存文件更新程序”上显示的标题
 *     UIStatus - “缓存文件更新程序”的 UI 状态(Unavailable, Hidden, Visible, Complete)
 *     UpdateTarget - Local 代表由 CachedFileUpdater 更新; Remote 代表由 app 更新
 *     UIRequested - 需要显示“缓存文件更新程序”的 UI 时触发的事件
 *     FileUpdateRequested - 当 app 激活缓存文件更新程序时,会触发 FileUpdateRequested 事件(事件参数:CachedFileUpdaterActivatedEventArgs)
 *     
 * CachedFileUpdaterActivatedEventArgs
 *     Request - 返回 FileUpdateRequest 类型的对象
 *     
 * FileUpdateRequest
 *     File - 关联的文件
 *     ContentId - 关联的文件标识
 *     Status - 文件的更新状态(FileUpdateStatus 枚举。Incomplete, Complete, UserInputNeeded, CurrentlyUnavailable, Failed, CompleteAndRenamed)
 *     GetDeferral() - 获取异步操作对象,同时开始异步操作,之后通过 Complete() 通知完成异步操作
 */

using System;
using Windows.ApplicationModel.Activation;
using Windows.Storage;
using Windows.Storage.Provider;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace CachedFileUpdaterProvider
{
    public sealed partial class MyCachedFileUpdater : Page
    {
        private CachedFileUpdaterUI _cachedFileUpdaterUI;
        private FileUpdateRequest _fileUpdateRequest;
        private CoreDispatcher _dispatcher = Windows.UI.Xaml.Window.Current.Dispatcher;

        public MyCachedFileUpdater()
        {
            this.InitializeComponent();
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            // 获取 CachedFileUpdaterUI 对象
            var args = (CachedFileUpdaterActivatedEventArgs)e.Parameter;
            _cachedFileUpdaterUI = args.CachedFileUpdaterUI;

            _cachedFileUpdaterUI.Title = "缓存文件更新程序";

            _cachedFileUpdaterUI.FileUpdateRequested += _cachedFileUpdaterUI_FileUpdateRequested;
            _cachedFileUpdaterUI.UIRequested += _cachedFileUpdaterUI_UIRequested;
        }

        // 需要显示 CachedFileUpdater 的 UI 时(即当 FileUpdateRequest.Status 等于 UserInputNeeded 时),会调用此事件处理器
        async void _cachedFileUpdaterUI_UIRequested(CachedFileUpdaterUI sender, object args)
        {
            await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                Windows.UI.Xaml.Window.Current.Content = this;
                lblMsg.Text = "FileUpdateStatus: " + _fileUpdateRequest.Status.ToString();
            });
        }

        void _cachedFileUpdaterUI_FileUpdateRequested(CachedFileUpdaterUI sender, FileUpdateRequestedEventArgs args)
        {
            _fileUpdateRequest = args.Request;
            FileUpdateRequestDeferral fileUpdateRequestDeferral = _fileUpdateRequest.GetDeferral();

            if (_cachedFileUpdaterUI.UpdateTarget == CachedFileTarget.Local) // 由 CachedFileUpdater 更新 CachedFile(CachedFileTarget.Local 方式)
            {
                // 显示 CachedFileUpdater 的 UI
                if (_cachedFileUpdaterUI.UIStatus == UIStatus.Hidden)
                {
                    _fileUpdateRequest.Status = FileUpdateStatus.UserInputNeeded;
                    fileUpdateRequestDeferral.Complete();
                }
            }
            else if (_cachedFileUpdaterUI.UpdateTarget == CachedFileTarget.Remote) // 由 app 更新 CachedFile(CachedFileTarget.Remote 方式)
            {
                // CachedFileUpdater 返回给 app 一个 FileUpdateStatus 状态
                _fileUpdateRequest.Status = FileUpdateStatus.Complete;
                fileUpdateRequestDeferral.Complete();
            }
        }

        private async void btnUpdate_Click_1(object sender, RoutedEventArgs e)
        {
            FileUpdateRequestDeferral fileUpdateRequestDeferral = _fileUpdateRequest.GetDeferral();

            // 由 CachedFileUpdater 更新 CachedFile,然后返回给 app 一个 FileUpdateStatus 状态
            await FileIO.AppendTextAsync(_fileUpdateRequest.File, Environment.NewLine + "由 CachedFileUpdater 更新:" + DateTime.Now.ToString());

            string fileContent = await FileIO.ReadTextAsync(_fileUpdateRequest.File);

            lblMsg.Text = "文件名: " + _fileUpdateRequest.File.Name;
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "文件内容: " + fileContent;

            _fileUpdateRequest.Status = FileUpdateStatus.Complete;
            fileUpdateRequestDeferral.Complete();

            btnUpdate.IsEnabled = false;
        }
    }
}


3、判断程序是否是由文件打开选取器激活或者是否是由缓存文件更新程序激活
App.xaml.cs

// 通过文件打开选取器激活应用程序时所调用的方法
protected override void OnFileOpenPickerActivated(FileOpenPickerActivatedEventArgs args)
{
    var rootFrame = new Frame();
    rootFrame.Navigate(typeof(MyOpenPicker), args);
    Window.Current.Content = rootFrame;

    Window.Current.Activate();
}

// 通过缓存文件更新程序(CachedFileUpdater)激活应用程序时所调用的方法
protected override void OnCachedFileUpdaterActivated(CachedFileUpdaterActivatedEventArgs args)
{
    var rootFrame = new Frame();
    rootFrame.Navigate(typeof(MyCachedFileUpdater), args);
    Window.Current.Content = rootFrame;

    Window.Current.Activate();
}



二、在 app 中调用 CachedFileUpdater

1、演示如何调用 CachedFileUpdater(缓存文件更新程序)
Picker/CachedFileUpdaterDemo.xaml

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

    <Grid Background="Transparent">
        <StackPanel Margin="120 0 0 0">

            <TextBlock Name="lblMsg" FontSize="14.667" />

            <Button Name="btnGetCachedFile" Content="打开 Provider 提供的 CachedFile" Click="btnGetCachedFile_Click_1" Margin="0 10 0 0" />

            <Button Name="btnReadCachedFile" Content="由 CachedFileUpdater 更新文件" Click="btnReadCachedFile_Click_1" Margin="0 10 0 0" />

            <Button Name="btnWriteCachedFile" Content="由 app 更新文件" Click="btnWriteCachedFile_Click_1" Margin="0 10 0 0" />
            
        </StackPanel>
    </Grid>
</Page>

Picker/CachedFileUpdaterDemo.xaml.cs

/*
 * 演示如何调用 CachedFileUpdater(缓存文件更新程序)
 * 
 * 流程:
 * 1、单击“打开 Provider 提供的 CachedFile”按钮,以弹出打开文件对话框
 * 2、在弹出的对话框中选择 CachedFileUpdaterProvider,以打开 CachedFileUpdaterProvider 项目中的 MyOpenPicker.xaml
 * 3、在 provider 中单击“提供一个 CachedFile”按钮,以打开一个文件,同时将此文件关联到 CachedFileUpdater
 * 4、如果在 provider 选择了“提供一个由 Local 更新的 CachedFile”则转到(5);如果在 provider 选择了“提供一个由 Remote 更新的 CachedFile”则转到(6)
 * 
 * 5、单击“由 CachedFileUpdater 更新文件”按钮,激活 CachedFileUpdater,获取由 CachedFileUpdater 修改后的文件(CachedFileUpdater 的 Local 方式)
 * 6、单击“由 app 更新文件”按钮,会在 app 端更指定的 CachedFile,需要的话可以激活 CachedFileUpdater 做一些别的处理(CachedFileUpdater 的 Remote 方式)
 * 
 * 
 * 注:app 代表调用方,provider 代表缓存文件提供方,CachedFileUpdater 代表缓存文件更新程序
 */

using System;
using Windows.Storage;
using Windows.Storage.AccessCache;
using Windows.Storage.Pickers;
using Windows.Storage.Provider;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace XamlDemo.Picker
{
    public sealed partial class CachedFileUpdaterDemo : Page
    {
        private string _cachedFileToken;

        public CachedFileUpdaterDemo()
        {
            this.InitializeComponent();
        }

        private async void btnGetCachedFile_Click_1(object sender, RoutedEventArgs e)
        {
            if (XamlDemo.Common.Helper.EnsureUnsnapped())
            {
                FileOpenPicker openPicker = new FileOpenPicker();
                openPicker.FileTypeFilter.Add(".txt");

                // 弹出打开文件对话框后,选择 CachedFileUpdaterProvider,以获取 CachedFile
                StorageFile file = await openPicker.PickSingleFileAsync();
                if (file != null)
                {
                    _cachedFileToken = StorageApplicationPermissions.FutureAccessList.Add(file);
                    string fileContent = await FileIO.ReadTextAsync(file);

                    lblMsg.Text = "文件名: " + file.Name;
                    lblMsg.Text += Environment.NewLine;
                    lblMsg.Text += "文件内容: " +  fileContent;
                }
                else
                {
                    lblMsg.Text = "取消了";
                }
            }
        }

        // 由 CachedFileUpdater 更新文件(CachedFileUpdater 的 Local 方式)
        private async void btnReadCachedFile_Click_1(object sender, RoutedEventArgs e)
        {
            if (!string.IsNullOrEmpty(_cachedFileToken))
            {
                StorageFile file = await StorageApplicationPermissions.FutureAccessList.GetFileAsync(_cachedFileToken);
                string fileContent = await FileIO.ReadTextAsync(file);

                lblMsg.Text = "文件名: " + file.Name;
                lblMsg.Text += Environment.NewLine;
                lblMsg.Text += "文件内容: " + fileContent;
            }
        }

        // 由 app 更新文件(CachedFileUpdater 的 Remote 方式)
        private async void btnWriteCachedFile_Click_1(object sender, RoutedEventArgs e)
        {
            if (!string.IsNullOrEmpty(_cachedFileToken))
            {
                StorageFile file = await StorageApplicationPermissions.FutureAccessList.GetFileAsync(_cachedFileToken);

                // 开始异步更新操作(不需要激活 CachedFileUpdater 的话可以不走这一步)
                CachedFileManager.DeferUpdates(file);
                
                // 更新文件
                await FileIO.AppendTextAsync(file, Environment.NewLine + "由 app 更新:" + DateTime.Now.ToString());

                // 通知系统已完成异步操作(之前激活的 CachedFileUpdater 会返回一个 FileUpdateStatus)
                FileUpdateStatus status = await CachedFileManager.CompleteUpdatesAsync(file);

                lblMsg.Text = status.ToString();
                lblMsg.Text += Environment.NewLine;

                if (status == FileUpdateStatus.Complete)
                {
                    string fileContent = await FileIO.ReadTextAsync(file);

                    lblMsg.Text += "文件名: " + file.Name;
                    lblMsg.Text += Environment.NewLine;
                    lblMsg.Text += "文件内容: " + fileContent;
                }
            }
        }
    }
}



OK
[源码下载]