【问题标题】:What is the alternative for BackgroundWorker in Windows 8.1 Universal Apps?Windows 8.1 通用应用程序中 BackgroundWorker 的替代方案是什么?
【发布时间】:2015-03-11 05:57:33
【问题描述】:

我正在将我的 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 有什么替代方案吗?

【问题讨论】:

    标签: c# win-universal-app


    【解决方案1】:

    恕我直言,即使对于桌面,Task&lt;T&gt;Progress&lt;T&gt; 类也提供了一个很好的替代 BackgroundWorker,它们都在 Windows Phone 8.1 上受支持。 Task&lt;T&gt; 类提供了启动然后干净地等待后台操作的机制,而 Progress&lt;T&gt; 类提供了报告进度的机制(不是您的示例或问题的一部分,但我提到它是因为这是一件事 @987654327 @ 和 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() 事件处理程序……尽管您的代码示例实际上并未提出任何机制,实际后台操作代码甚至可以通过这种机制检测取消)。

    请注意,使用async/await,您的任务也可以根据需要返回一个值,通过Task&lt;T&gt; 类型而不是Task。上面的示例可以很容易地修改以适应这一点,async/await 的特性是我喜欢它而不是 BackgroundWorker 的最大原因之一(它没有干净的、编译器支持的机制来从后台操作)。

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

    【讨论】:

    • 谢谢@Peter。我会试试这个。但是为什么 callBackFunction 参数被删除了?你能也回答我的第二个问题吗?
    • 我删除了该参数,因为 async/await 模式不需要它。正如我在示例调用代码中所示,您可以直接在await 调用async 方法之后直接调用该方法,而不是传递要调用的委托。至于第二个问题,是stackoverflow.com/questions/19886107/…的骗子
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-07
    • 2013-06-23
    • 1970-01-01
    • 1970-01-01
    • 2016-01-16
    相关资源
    最近更新 更多