使用 TPL 时如何调用 UI 线程上的方法? [英] How do I invoke a method on the UI thread when using the TPL?

查看:37
本文介绍了使用 TPL 时如何调用 UI 线程上的方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个使用 TPL 在后台执行多项任务的 MVVM 应用程序.任务需要向 UI 报告进度,以便可以更新进度对话框.由于应用程序是 MVVM,进度对话框绑定到名为 Progress 的视图模型属性,该属性由具有签名 UpdateProgress(int increment) 的视图模型方法更新.后台任务需要调用该方法报告进度.

I am working on an MVVM app that performs several tasks in the background, using TPL. The tasks need to report progress to the UI so that a progress dialog can be updated. Since the app is MVVM, the progress dialog is bound to a view model property named Progress, which is updated by a view model method with the signature UpdateProgress(int increment). The background tasks need to call this method to report progress.

我使用一种方法来更新属性,因为它允许每个任务以不同的量递增 Progress 属性.所以,如果我有两个任务,第一个任务花费的时间是第二个任务的四倍,那么第一个任务调用 UpdateProgress(4),第二个任务调用 UpdateProgress(1).因此,第一个任务完成时进度为 80%,第二个任务完成时进度为 100%.

I use a method to update the property because it lets each task increment the Progress property by different amounts. So, if I have two tasks, and the first one takes four times as long as the second, the first task calls UpdateProgress(4), and the second task calls UpdateProgress(1). So, progress is at 80% when the first task completes, and at 100% when the second task completes.

我的问题非常简单:如何从后台任务调用视图模型方法?代码如下.感谢您的帮助.

My question is really pretty simple: How do I call the view model method from my background tasks? Code is below. Thanks for your help.

任务使用 Parallel.ForEach(),代码如下:

The tasks use Parallel.ForEach(), in code that looks like this:

private void ResequenceFiles(IEnumerable<string> fileList, ProgressDialogViewModel viewModel)
{
    // Wrap token source in a Parallel Options object
    var loopOptions = new ParallelOptions();
    loopOptions.CancellationToken = viewModel.TokenSource.Token;

    // Process images in parallel
    try
    {
        Parallel.ForEach(fileList, loopOptions, sourcePath =>
        {
            var fileName = Path.GetFileName(sourcePath);
            if (fileName == null) throw new ArgumentException("File list contains a bad file path.");
            var destPath = Path.Combine(m_ViewModel.DestFolder, fileName);
            SetImageTimeAttributes(sourcePath, destPath);

            // This statement isn't working
            viewModel.IncrementProgressCounter(1);
        });
    }
    catch (OperationCanceledException)
    {
        viewModel.ProgressMessage = "Image processing cancelled.";
    }
}

语句 viewModel.IncrementProgressCounter(1) 没有抛出异常,但它没有进入主线程.这些任务是从 MVVM ICommand 对象调用的,代码如下所示:

The statement viewModel.IncrementProgressCounter(1) isn't throwing an exception, but it's not getting through to the main thread. The tasks are called from MVVM ICommand objects, in code that looks like this:

public void Execute(object parameter)
{
    ...

    // Background Task #2: Resequence files
    var secondTask = firstTask.ContinueWith(t => this.ResequenceFiles(fileList, progressDialogViewModel));

    ...
}

推荐答案

要将方法调用编组到主 UI 线程,您可以使用 Dispatcher 的 InvokeMethod 方法.如果您使用像 Carliburn 这样的 MVVM 框架,它会对 Dispatcher 进行抽象,因此您可以使用 Execute.OnUIThread(Action) 执行几乎相同的操作.

To marshall method calls to the main UI thread you can use Dispatcher's InvokeMethod method. If you use MVVM Frameworks like Carliburn it has abstractions over Dispatcher so you can do almost the same thing using Execute.OnUIThread(Action).

查看这篇 Microsoft 文章,了解如何使用 Dispatcher.

Check this Microsoft article on how to use Dispatcher.

这篇关于使用 TPL 时如何调用 UI 线程上的方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆