2015-03-11 3 views
2

Я переношу свое приложение Windows Phone в Windows Universal Apps. В приложении «Телефон» я использовал BackgroundWorker для извлечения базы данных, а затем в пользовательском интерфейсе. Ниже приведен класс, который я подготовил в Windows Phone 8 и как он был вызван.Что является альтернативой для BackgroundWorker в Windows 8.1 Universal Apps?

public class TestBackgroundWorker 
{ 
    private BackgroundWorker backgroundWorker; 
    ProgressIndicator progressIndicator; 

    public delegate void functionToRunInBackground(); 
    public functionToRunInBackground currentFunctionToExecute; 

    public delegate void callbackFunction(); 
    public callbackFunction functionToSendResult; 

    private bool isCancellationSupported; 


    private string message; 


    /// <summary> 
    /// 
    /// </summary> 
    /// <param name="functionNameToExecute">specifies function name to be executed in background</param> 
    /// <param name="isCancellable">Flag which specifies whether the operation is cancellable or not</param> 
    /// <param name="functionNameWhichGetsResult">Specifies call back function to be executed after the completion of operation</param> 
    public MCSBackgroundWorker(functionToRunInBackground functionNameToExecute, bool isCancellable, string messageToDisplay, callbackFunction functionNameWhichGetsResult) 
    { 
     currentFunctionToExecute = functionNameToExecute; 
     functionToSendResult = functionNameWhichGetsResult; 
     isCancellationSupported = isCancellable; 
     message = messageToDisplay; 
     backgroundWorker = new BackgroundWorker(); 
     backgroundWorker.WorkerSupportsCancellation = isCancellable; 
     backgroundWorker.DoWork += backgroundWorker_DoWork; 
     backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted; 
    } 

    void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     deactivateProgressIndicator(); 
     functionToSendResult(); 
    } 

    void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     if (currentFunctionToExecute != null) 
     { 
      currentFunctionToExecute(); 
     } 
    } 


    public void cancelBackgroundOperation() 
    { 
     if (isCancellationSupported == true) 
     { 
      backgroundWorker.CancelAsync(); 
     } 
    } 


    public void Start() 
    { 
     backgroundWorker.RunWorkerAsync(); 
     activateProgressIndicator(); 
    } 


    void activateProgressIndicator() 
    { 
     Deployment.Current.Dispatcher.BeginInvoke(() => 
     { 
      var currentPage = App.RootFrame.Content as PhoneApplicationPage; 
      SystemTray.SetIsVisible(currentPage, true); 
      SystemTray.SetOpacity(currentPage, 0.5); 
      SystemTray.SetBackgroundColor(currentPage, Colors.White); 
      SystemTray.SetForegroundColor(currentPage, Colors.Black); 

      progressIndicator = new ProgressIndicator(); 
      progressIndicator.IsVisible = true; 
      progressIndicator.IsIndeterminate = true; 
      progressIndicator.Text = message; 

      SystemTray.SetProgressIndicator(currentPage, progressIndicator); 

     }); 

    } 

    void deactivateProgressIndicator() 
    { 
     Deployment.Current.Dispatcher.BeginInvoke(() => 
     { 
      if (progressIndicator != null) 
      { 
       var currentPage = App.RootFrame.Content as PhoneApplicationPage; 
       progressIndicator.IsVisible = false; 
       SystemTray.SetIsVisible(currentPage, false); 

      } 

     }); 
    } 


    public bool isBackgroundWorkerBusy() 
    { 
     return backgroundWorker != null ? backgroundWorker.IsBusy : false; 
    } 

} 

}

И называя, что, как показано ниже, чтобы запустить процесс в фоновом режиме.

private void loadReports() 
    { 
     bgWorker = new TestBackgroundWorker(loadReportsFromDB, true, "Loading...", showReports); 
     bgWorker.Start(); 
    } 

Здесь loadReprtsFromDB и showReports - это две функции.

Вопросы:

  1. Может кто-нибудь подскажет, как достичь то же самое в Windows, 8.1?

  2. Есть ли альтернативные варианты для PhoneApplicationService.Current.State?

ответ

2

ИМХО, даже для рабочего стола, Task<T> и Progress<T> классы предлагают хорошую альтернативу BackgroundWorker, и они оба поддерживаются на Windows Phone 8.1. Класс Task<T> обеспечивает механизм запуска, а затем чистоту ожидания фоновых операций, тогда как класс Progress<T> предоставляет механизм для отчетности о прогрессе (не часть вашего примера или вопроса, но я упоминаю это, потому что это одна вещь Task, а также async/await не предоставляется от BackgroundWorker).

Ваш пример может быть изменен на что-то вроде этого:

public class TestBackgroundWorker 
{ 
    private Task _task; 
    private CancellationTokenSource _cancelSource; 

    public CancellationToken CancellationToken 
    { 
     get { return _cancelSource != null ? _cancelSource.Token : null; } 
    } 

    ProgressIndicator progressIndicator; 

    public readonly Action<TestBackgroundWorker> currentFunctionToExecute; 

    private string message; 

    /// <summary> 
    /// 
    /// </summary> 
    /// <param name="functionNameToExecute">specifies function name to be executed in background</param> 
    /// <param name="isCancellable">Flag which specifies whether the operation is cancellable or not</param> 
    /// <param name="functionNameWhichGetsResult">Specifies call back function to be executed after the completion of operation</param> 
    public MCSBackgroundWorker(Action<TestBackgroundWorker> functionNameToExecute, bool isCancellable, string messageToDisplay) 
    { 
     currentFunctionToExecute = functionNameToExecute; 
     _cancelSource = isCancellable ? new CancellationTokenSource() : null; 
     message = messageToDisplay; 
    } 

    public void cancelBackgroundOperation() 
    { 
     if (_cancelSource != null) 
     { 
      _cancelSource.Cancel(); 
     } 
    } 

    public async Task Start() 
    { 
     activateProgressIndicator(); 
     _task = Task.Run(() => currentFunctionToExecute(this)); 
     await _task; 
     _task = null; 
     deactivateProgressIndicator(); 
    } 

    void activateProgressIndicator() 
    { 
     // In theory, you should not need to use Dispatcher here with async/await. 
     // But without a complete code example, it's impossible for me to 
     // say for sure, so I've left it as-is. 
     Deployment.Current.Dispatcher.BeginInvoke(() => 
     { 
      var currentPage = App.RootFrame.Content as PhoneApplicationPage; 
      SystemTray.SetIsVisible(currentPage, true); 
      SystemTray.SetOpacity(currentPage, 0.5); 
      SystemTray.SetBackgroundColor(currentPage, Colors.White); 
      SystemTray.SetForegroundColor(currentPage, Colors.Black); 

      progressIndicator = new ProgressIndicator(); 
      progressIndicator.IsVisible = true; 
      progressIndicator.IsIndeterminate = true; 
      progressIndicator.Text = message; 

      SystemTray.SetProgressIndicator(currentPage, progressIndicator); 
     }); 
    } 

    void deactivateProgressIndicator() 
    { 
     // Likewise. 
     Deployment.Current.Dispatcher.BeginInvoke(() => 
     { 
      if (progressIndicator != null) 
      { 
       var currentPage = App.RootFrame.Content as PhoneApplicationPage; 
       progressIndicator.IsVisible = false; 
       SystemTray.SetIsVisible(currentPage, false); 
      } 
     }); 
    } 

    public bool isBackgroundWorkerBusy() 
    { 
     return _task != null; 
    } 
} 

Тогда вы могли бы использовать это что-то вроде этого:

private async Task loadReports() 
{ 
    bgWorker = new TestBackgroundWorker(loadReportsFromDB, true, "Loading..."); 
    await bgWorker.Start(); 
    showReports(); 
} 

void loadReportsFromDB(TaskBackgroundWorker worker) 
{ 
    while (...) 
    { 
     if (worker.CancellationToken.IsCancellationRequested) 
     { 
      return; // or whatever 
     } 
    } 
} 

Чтобы справиться с отменой, то functionNameToExecute делегат должен был бы быть для метод, который принимает экземпляр TaskBackgroundWorker в качестве параметра, чтобы он мог получить значение свойства CancellationToken, чтобы проверить отмену (аналогично обработчику событий DoWork() & hellip; хотя ваш код e xample на самом деле не предлагал никакого механизма, посредством которого фактический код операции фона даже обнаруживал бы отмену).

Обратите внимание, что с async/await, ваша задача также может возвращать значение, если вы хотите, через Task<T> типа вместо Task. Вышеприведенный пример может быть легко изменен для его соответствия, и эта особенность async/await является одной из основных причин, по которой я предпочитаю ее более BackgroundWorker (у которой нет чистого механизма, поддерживающего компилятор для возврата результатов из фоновой операции).

Предостережение: Отсутствие полного примера кода для начала, я не хочу пытаться на самом деле скомпилировать и протестировать любой код. Таким образом, вышесказанное строго «автор-автор». Этого достаточно для иллюстрации, но я заранее извиняюсь за любые опечатки, которые могут существовать.

+0

Спасибо @Peter. Я попробую это. Но почему параметр callBackFunction был удален ?.Можете ли вы ответить на мой второй вопрос? –

+0

Я удалил этот параметр, потому что он не нужен с шаблоном 'async' /' await'. Как я показал в примере кода вызова, вместо передачи вызывающего делегата, вы можете просто вызвать метод непосредственно после 'await'ing метода' async'. Что касается второго вопроса, это обман http://stackoverflow.com/questions/19886107/phoneapplicationservice-current-state-equivalent-in-windows-8 –

Смежные вопросы