背水一战 Windows 10 (97) - 选取器: CachedFileUpdater

[源码下载]


背水一战 Windows 10 (97) - 选取器: CachedFileUpdater



作者:webabcd


介绍
背水一战 Windows 10 之 选取器

  • CachedFileUpdater(缓存文件更新程序)



示例
1、演示如何开发自定义缓存文件更新程序
CachedFileUpdaterProvider/App.xaml.cs

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

            Window.Current.Activate();
        }

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="10 0 10 10">

            <TextBlock Name="lblMsg" Margin="5" />

            <Button Name="btnUpdate" Content="更新 CachedFile(由 CachedFileUpdater 更新 CachedFile)" Click="btnUpdate_Click" Margin="5" />

        </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;

            base.OnNavigatedTo(e);
        }

        // 需要显示 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();
            });
        }

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

            if (_cachedFileUpdaterUI.UpdateTarget == CachedFileTarget.Local) // 由 CachedFileUpdater 更新 CachedFile(CachedFileTarget.Local 方式)
            {
                // 开始激活 CachedFileUpdater 时,是 UIStatus.Hidden 状态的
                if (_cachedFileUpdaterUI.UIStatus == UIStatus.Hidden)
                {
                    // 下面针对两种方式分别写示例

                    // 方式一:直接更新文件,并设置为 FileUpdateStatus.Complete 状态,最后完成
                    if (DateTime.Now.Second % 2 == 0)
                    {
                        await FileIO.AppendTextAsync(_fileUpdateRequest.File, Environment.NewLine + "由 CachedFileUpdater 更新:" + DateTime.Now.ToString());
                        _fileUpdateRequest.Status = FileUpdateStatus.Complete;
                        fileUpdateRequestDeferral.Complete();
                    }
                    // 方式二:设置为 FileUpdateStatus.UserInputNeeded 状态,并完成,之后会再次触发这个事件,并且变为 UIStatus.Visible 状态,弹出本页界面,
                    // 这样的话可以在用户做一些操作之后再更新文件(参见下面的 btnUpdate_Click 部分)
                    else
                    {
                        _fileUpdateRequest.Status = FileUpdateStatus.UserInputNeeded;
                        fileUpdateRequestDeferral.Complete();
                    }
                }
            }
            else if (_cachedFileUpdaterUI.UpdateTarget == CachedFileTarget.Remote) // 由 app 更新 CachedFile(CachedFileTarget.Remote 方式)
            {
                // 这里可以拿到 app 更新后的文件的结果
                string textContent = await FileIO.ReadTextAsync(_fileUpdateRequest.File);
                // 但是这里不能修改这个文件,否则会报错
                // await FileIO.AppendTextAsync(_fileUpdateRequest.File, Environment.NewLine + "由 CachedFileUpdater 更新:" + DateTime.Now.ToString());

                // CachedFileUpdater 返回给 app 一个 FileUpdateStatus 状态
                _fileUpdateRequest.Status = FileUpdateStatus.Complete;
                fileUpdateRequestDeferral.Complete();
            }
        }

        private async void btnUpdate_Click(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;
        }
    }
}


2、打开一个文件,并关联到 CachedFileUpdater
CachedFileUpdaterProvider/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();
        }

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="10 0 10 10">

            <TextBlock Name="lblMsg" Margin="5" />

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

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

        </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)
        {
            // 获取 FileOpenPickerUI 对象(从 App.xaml.cs 传来的)
            var args = (FileOpenPickerActivatedEventArgs)e.Parameter;
            _fileOpenPickerUI = args.FileOpenPickerUI;

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

            base.OnNavigatedTo(e);
        }

        // 本 CachedFile 用于从 Local 更新(由 CachedFileUpdater 更新 CachedFile)
        private async void btnPickCachedFileLocal_Click(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 更新(由 app 更新 CachedFile)
        private async void btnPickCachedFileRemote_Click(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);
        }
    }
}


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

<Page
    x:Class="Windows10.Picker.CachedFileUpdaterDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Windows10.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="10 0 10 10">

            <TextBlock Name="lblMsg" Margin="5" />

            <Button Name="btnGetCachedFile" Content="打开 Provider 提供的 CachedFile" Click="btnGetCachedFile_Click" Margin="5" />

            <Button Name="btnReadCachedFile" Content="由 CachedFileUpdater 更新文件" Click="btnReadCachedFile_Click" Margin="5" />

            <Button Name="btnWriteCachedFile" Content="由 app 更新文件" Click="btnWriteCachedFile_Click" Margin="5" />

        </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 Windows10.Picker
{
    public sealed partial class CachedFileUpdaterDemo : Page
    {
        private string _cachedFileToken;

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

        private async void btnGetCachedFile_Click(object sender, RoutedEventArgs e)
        {
            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(object sender, RoutedEventArgs e)
        {
            if (!string.IsNullOrEmpty(_cachedFileToken))
            {
                try
                {
                    StorageFile file = await StorageApplicationPermissions.FutureAccessList.GetFileAsync(_cachedFileToken);
                    // 获取的文件是 CachedFile,且是 CachedFileUpdater 的 Local 方式
                    // 如此就会激活 CachedFileUpdater,由 CachedFileUpdater 更新文件并返回
                    string fileContent = await FileIO.ReadTextAsync(file);

                    lblMsg.Text = "文件名: " + file.Name;
                    lblMsg.Text += Environment.NewLine;
                    lblMsg.Text += "文件内容: " + fileContent;
                }
                catch (Exception ex)
                {
                    lblMsg.Text = ex.ToString();
                }
            }
        }

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

                    // 开始异步更新操作(不需要激活 CachedFileUpdater 的话可以不走这一步)
                    CachedFileManager.DeferUpdates(file);

                    // 更新文件
                    await FileIO.AppendTextAsync(file, Environment.NewLine + "由 app 更新:" + DateTime.Now.ToString());

                    // 通知系统已完成异步操作(之前激活的 CachedFileUpdater 会返回一个 FileUpdateStatus)
                    // 更新的文件是 CachedFile,且是 CachedFileUpdater 的 Remote 方式,即 app 更新
                    // 更新后会激活 CachedFileUpdater,在 CachedFileUpdater 中可以拿到更新后的文件
                    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;
                    }
                }
                catch (Exception ex)
                {
                    lblMsg.Text = ex.ToString();
                }
            }
        }
    }
}



OK
[源码下载]

posted @ 2018-06-15 08:45  webabcd  阅读(855)  评论(0编辑  收藏  举报