Статьи

Как использовать контракт обновления кэшированных файлов в приложении Windows 8

 Прежде всего:
код этого блога доступен здесь .

Что это ?

Контракты Cached File Updater просто заявляют, что ваше приложение отвечает за управление одним или несколькими его файлами. Это действительно полезно для «приложений для управления файлами».

Вы можете использовать «CachedFileUpdater», чтобы сделать действительно интересные вещи:

  • Активируйте приложение, прежде чем читать файл.
  • Активируйте приложение после записи в ваш файл.
  • Установите ваш файл только для чтения.
  • Используйте кэшированную версию вашего файла, если Интернет недоступен.
  • Отказать в доступе к файлу, если интернет недоступен

Я имею в виду «файл», но это можно сделать с любым файлом вашего приложения.

Как это использовать ?

Использование этого контракта выполняется в 4 этапа, один из которых необязательный.

1) Объявить договор в манифесте.

Первое, что касается любых контрактов, это объявить контракт в манифесте приложения. Просто добавьте это:
cachedFileUpdaterManifest

2) Определите некоторые триггеры в вашем файле.

Когда вы создаете файл в своем приложении, вы можете определить для него некоторые триггеры, используя метод CachedFileUpdater.SetUpdateInformation . Это простой вызов, и он принимает 5 аргументов:

  1. Сам файл хранилища.
  2. Идентификатор, который будет передан вашему приложению при активации этого файла.
  3. ReadActivationMode, который определяет, активировано ли приложение до доступа к файлу или нет.
  4. WriteActivationMode, который сообщает, активировано ли ваше приложение после того, как другое приложение записывает «на» ваш файл или файл должен быть доступен только для чтения.
  5. CachedFileOptions, который сообщает, как «ведет себя» доступ к файлу при отсутствии подключения к Интернету.

Вот пример, который просит ваше приложение быть активированным после того, как другое приложение пишет в ваш файл:

CachedFileUpdater.SetUpdateInformation(fileCreated,
                            "A content id to identify the file.",
                            ReadActivationMode.NotNeeded,
                            WriteActivationMode.AfterWrite,
                            CachedFileOptions.None);
3) Переопределить метод OnCachedFileUpdaterActivation приложения.

После этого вы можете переопределить метод OnCachedFileUpdaterActivation вашего приложения. Предоставленный аргумент даст вам свойство «CachedFileUpdaterUI» с некоторой интересной информацией:

  • Событие «FileUpdateRequested», которое возникает при достижении ранее определенных триггеров.
  • Свойство «UpdateTarget» указывает, является ли файл для обновления «удаленным» (файл в вашем приложении) или «локальным» (файл в другом приложении).
  • Событие UIRequested возникает, когда пользователю необходимо предоставить некоторые данные, чтобы иметь возможность обновить файл. Мы пойдем дальше на этом позже

Когда вам не нужно показывать пользователю какой-либо пользовательский интерфейс, вам просто нужно захватить файл при возникновении события FileUpdateRequested и что-то сделать с файлом. Если необходимо обновить локальный файл, вы можете вызвать метод UpdateLocalFile и предоставить обновленный файл.

Кроме того, вы должны установить «args.Request.Status» в зависимости от успешности операции (в нашем случае FileUpdateStatus.Complete).
Вот пример:

protected override void
     OnCachedFileUpdaterActivated(CachedFileUpdaterActivatedEventArgs args)
 {
     args.CachedFileUpdaterUI.FileUpdateRequested
          += OnCachedFileUpdaterUIFileUpdateRequested;
     base.OnCachedFileUpdaterActivated(args);
      
     //do not forget this
     Window.Current.Activate();
 }
 
 void OnCachedFileUpdaterUIFileUpdateRequested(CachedFileUpdaterUI sender,
         FileUpdateRequestedEventArgs args)
 {
     var deferral = args.Request.GetDeferral();
 
     var theContentId = args.Request.ContentId;
     var theTargetFile = args.Request.File;
 
     //Do something to the file
 
     //If the local file have to be updated, call do this :
     //StorageFile upToDateFile=null;
     //fill upToDateFile with the correct data
     //args.Request.UpdateLocalFile(upToDateFile);
 
     args.Request.Status=FileUpdateStatus.Complete
     deferral.Complete();
}
4) Попросите пользователя ввести некоторые данные (необязательно).

Если процесс обновления нуждается в этом, вы можете попросить пользователя ввести некоторые данные.

Для этого вы должны указать это в обработчике события FileUpdateRequested с помощью args.Request.Status и установить для него значение FileUpdateStatus.UserInputNeeded .

if (sender.UIStatus == UIStatus.Hidden)
{
    args.Request.Status = FileUpdateStatus.UserInputNeeded;
 
    //Can set a custom title
    sender.Title = "Requiring input for : " + args.Request.ContentId;
 
    return;
}

Затем возникает событие UIRequested, и вы должны установить содержимое окна в соответствии с вашим конкретным пользовательским интерфейсом в обработчике . Не забудьте сделать это в правильной ветке. Не забудьте сделать это в правильной ветке: создайте страницу в первом событии активации и используйте страницу Dispatcher для установки содержимого.

void CachedFileUpdaterUI_UIRequested(CachedFileUpdaterUI sender, object args)
{
    _specificUIPage.Dispatcher.RunAsync(
        CoreDispatcherPriority.Normal,
        () => { Window.Current.Content = _specificUIPage; });
}

Событие FileUpdateRequested будет вызвано еще раз, чтобы сообщить вам, что пользовательский интерфейс видим. В обработчике вы должны получить аргументы событий и передать их в свой пользовательский интерфейс. Пользовательский интерфейс будет отвечать за установку правильного значения статуса запроса. В моем случае я сохраняю args как статическое поле моего приложения.

public static FileUpdateRequestedEventArgs FileUpdateRequestedEventAr
void OnCachedFileUpdaterUIFileUpdateRequested(
      CachedFileUpdaterUI sender, FileUpdateRequestedEventArgs args)
{
    bool showSpecificUI = false;
 
    FileUpdateRequestedEventArgs = args;
 
    var deferral = args.Request.GetDeferral();
    if (sender.UIStatus == UIStatus.Hidden)
    {
        args.Request.Status = FileUpdateStatus.UserInputNeeded;
 
        //Can set a custom title for the UI
        sender.Title = "Requiring input for : "
            + args.Request.ContentId;
        deferral.Complete();
        return;
    }
 
    if (sender.UIStatus == UIStatus.Unavailable)
    {
    //failure
        args.Request.Status = FileUpdateStatus.Failed;
        deferral.Complete();
        return;
    }
 
    if (sender.UIStatus == UIStatus.Visible)
    {
        //Do nothing, the UI will do it for us.
        return;
    }
}

В моем пользовательском интерфейсе я просто устанавливаю статус и завершаю отсрочку, когда пользователь нажимает кнопку:

private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
    App.FileUpdateRequestedEventArgs
       .Request.Status = FileUpdateStatus.Complete;
    App.FileUpdateRequestedEventArgs
       .Request.GetDeferral().Complete();
}

InputNeeded

Почему это полезно с FileSavePicker?

В 8 Files In A Box, клиенте Dropbox для Windows 8, мы хотели иметь возможность сохранить файл и загрузить его непосредственно в пользовательский Dropbox.

Сначала я подумал, что это невозможно: как только средство выбора сохранения файлов предоставит файл запрашивающему приложению, мое приложение будет закрыто Windows 8, и у меня будет:

  • нет способа узнать, когда предоставленный файл полностью записан другим приложением.
  • нет процессорного времени, потому что мое приложение больше не работает.

Леонард, один из моих коллег по « Бесконечной площади», продемонстрировал мне, что я был неправ (а то, что невозможно, на самом деле не французское слово :)).

Фактически это можно сделать с помощью контракта Cached File Updater:

  1. Укажите файл обычным способом в интерфейсе выбора сохранения файла.
  2. Используйте для него триггер WriteActivationMode.AfterWrite.
  3. Запустите загрузку, когда мое приложение будет активировано после завершения записи.

Действительно простой :)для тех, кто лучше всех понимает код (как я :)), здесь фрагмент кода:

protected override void
   OnFileSavePickerActivated(FileSavePickerActivatedEventArgs args)
{
    base.OnFileSavePickerActivated(args);
 
    args.FileSavePickerUI.TargetFileRequested
          += FileSavePickerUI_TargetFileRequested;
}
 
async void FileSavePickerUI_TargetFileRequested(
       FileSavePickerUI sender,
       TargetFileRequestedEventArgs args)
{
    var fileCreated = await ApplicationData.Current
          .TemporaryFolder.CreateFileAsync("ThisIsACoolFileName");
     
    CachedFileUpdater.SetUpdateInformation(fileCreated,
                                "A content id to identify the file.",
                                ReadActivationMode.BeforeAccess,
                                WriteActivationMode.AfterWrite,
                                CachedFileOptions.None);
 
    args.Request.TargetFile = fileCreated;
 
}

Другие важные факты

1) не забудьте активировать ваше приложение.

Сначала мне не удалось заставить его работать: вызывался метод OnCachedFileUpdaterActivation, но событие OnCachedFileUpdaterUIFileUpdateRequested не вызывалось.

После некоторых исследований в интернете я наконец обнаружил, что вызов Windows.Current.Activate () для активации вашего приложения действительно необходим: не забывайте об этом :)!

2) мое приложение не активировано :-(

Наконец, я просто хочу напомнить вам, что приложение, запрашивающее файл, отвечает за уведомление Windows о том, что оно больше не использует файл (запись завершена). Так что, если ваше приложение не активировано, это может быть потому, что запрашивающее приложение просто не просит вас обновить файл.

Если вы используете (не реализуете, но используете ) FileSavePicker, пожалуйста, вызовите методы CachedFileManager, как в этом фрагменте из примера средства выбора файлов:

// Prevent updates to the remote version of the file until we
// finish making changes and call CompleteUpdatesAsync.
CachedFileManager.DeferUpdates(file);
// write to file
await FileIO.WriteTextAsync(file, file.Name);
// Let Windows know that we're finished changing the file so the other
//  app can update the remote version of the file.
// Completing updates may require Windows to ask for user input.
FileUpdateStatus status = await CachedFileManager.CompleteUpdatesAsync(file);
3) будьте осторожны с Диспетчером

Когда ваше приложение активировано, для него создается диспетчер. CachedFileUpdaterUI использует другой Dispatcher, и вы должны быть осторожны, чтобы быть правильным (вашим) при обновлении вашего пользовательского интерфейса. Например, когда вы устанавливаете содержимое своей Windows, не забудьте сделать это на Dispatcher.

Я позволю вам покопаться в моем прикрепленном коде для более полного примера.
Если вам нужен другой образец, вы можете загрузить и использовать образец средства выбора файлов на MSDN .

Это все на сегодня !