c# - Windows 8.1 通用应用程序中的 BackgroundWorker 的替代方案是什么?

标签 c# win-universal-app

我正在将 Windows Phone 应用程序迁移到 Windows 通用应用程序。在Phone App中,我使用BackgroundWorker进行数据库检索,然后显示在UI中。下面是我在 Windows Phone 8 中准备的类以及它的调用方式。

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 有其他替代方案吗?

最佳答案

恕我直言,即使对于桌面,Task<T>Progress<T>类(class)提供了一个很好的替代方案 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委托(delegate)需要用于接受 TaskBackgroundWorker 实例的方法。作为参数,以便它可以检索 CancellationToken用于检查取消的属性值(类似于 DoWork() 事件处理程序......尽管您的代码示例实际上并未建议实际后台操作代码甚至可以检测取消的任何机制)。

请注意,async/await ,如果您愿意,您的任务还可以通过 Task<T> 返回一个值输入而不是 Task 。可以轻松修改上面的示例以适应这一点以及 async 的功能。/await这是我更喜欢它而不是 BackgroundWorker 的最大原因之一(它没有干净的、编译器支持的机制来从后台操作返回结果)。

警告:由于缺乏完整的代码示例,我没有必要尝试实际编译和测试任何代码。所以上面的内容严格来说是“浏览器编写的”。出于说明的目的,它应该足够了,但对于可能存在的任何拼写错误,我提前表示歉意。

关于c# - Windows 8.1 通用应用程序中的 BackgroundWorker 的替代方案是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28979590/

相关文章:

c# - UWP:从主窗口控制第二个窗口

c# - 如何使用 Windows 10 创建特定于设备系列的项目,例如在 W8.1/WP8.1 上?

c# - 在 TFS 中,如何使用查询 (C#) 查找测试套件中的所有测试用例?

c# - Xamarin WCF BasicHttpBinding-未实现方法或操作

c# - 如何在本地运行 Windows 10 IOT 应用程序?

win-universal-app - 如何在UWP中设置任务栏进度条

c# - 获取一些用于检测的 Windows Phone 属性

c# - Selenium Internet Explorer 驱动程序、Kendo Mobile 和 Octopus Deploy

c# - 表达混合彩色区域

c# - 如何在没有 "Enviroment"的情况下获取 Windows 通用应用程序中某些特殊文件夹的路径