从两个任务更新进度条

时间:2018-01-31 11:21:30

标签: c# wpf

我正在尝试同时从两个单独的任务更新进度条。我已经尝试了很多方法,但没有取得多大成功。见下面的完整代码示例。在WPF中,添加一个进度条,将Maximum绑定到TextMax,将Value绑定到TextProgress,您会注意到进度条只填充到大约一半。

注意:这不是我的实际解决方案,只是我正在做的一个示例,它显示了我扔在一起的问题,请忽略代码样式/模式问题。

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;

namespace DelegateTesting
{
    public partial class MainWindow : Window
    {
        ResultsItemViewModel _ViewModel = new ResultsItemViewModel();
        public MainWindow()
        {
            InitializeComponent();
            DataContext = _ViewModel;
            TextProcessing();
        }
        private static void Method1(
            Action<int> reportProgress)
        {
            var progress = 0;

            for(int i = 0;i<100;i++)
            {
                //Thread.Sleep(200);
                reportProgress?.Invoke(++progress);
            }
        }
        private static void Method2(
            Action<int> reportProgress)
        {
            var progress = 0;

            for (int i = 0; i < 100; i++)
            {
                //Thread.Sleep(200);
                reportProgress?.Invoke(++progress);
            }
        }
        private async Task TextProcessing()
        {
            _ViewModel.TextMax += 100;
            _ViewModel.TextMax += 100;

            var dispatcher = Application.Current.Dispatcher;
            var reportProgress = dispatcher.MakeInvoker<int>(p => _ViewModel.TextProgress = p);

            await Task.WhenAll(
                Task.Run(() => Method1(reportProgress)),
                Task.Run(() => Method2(reportProgress)));
        }
    }
    public static class DispatcherHelper
    {
        public static Action<T> MakeInvoker<T>(
            this Dispatcher dispatcher,
            Action<T> action,
            DispatcherPriority priority = DispatcherPriority.Normal)
        {
            return o => dispatcher.BeginInvoke(priority, action, o);
        }
    }
    public class ResultsItemViewModel : INotifyPropertyChanged
    {
        int _textProgress, _textMax;
        public int TextProgress
        {
            get => _textProgress;
            set
            {
                _textProgress = value;
                NotifyPropertyChanged();
            }
        }

        public int TextMax
        {
            get => _textMax;
            set
            {
                _textMax = value;
                NotifyPropertyChanged();
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        {
            var handler = PropertyChanged;
            handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

1 个答案:

答案 0 :(得分:1)

您没有等待TextProcessing。你不能只在中间拨打await。您可以一直异步或根本不同步。 此外,在构造函数中工作不是一个好习惯。

为了使其正常工作,您必须允许WPF为您处理异步调用。我假设你想在有人做某事时开始行动,例如:

protected async void Button_OnClick(Object sender, EventArgs e)
{
    await TextProcessing();
}

您始终可以将其绑定到启动窗口或类似事件的事件。

说实话,你的代码对我来说很不清楚,所以这可能会帮助你理解你真正需要的东西:

   int _textProgress, _textMax;
    public int TextProgress
    {
        get => _textProgress;
        set
        {
            _textProgress = value;
            NotifyPropertyChanged();
        }
    }

    public int TextMax
    {
        get => _textMax;
        set
        {
            _textMax = value;
            NotifyPropertyChanged();
        }
    }
 protected async void Button_OnClick(Object sender, EventArgs e)
    {
        TextMax = 0;

        var t1 = Task.Run(() => {
            TextProgress += 50;
        });
        var t2 = Task.Run(() => {
            TextProgress += 50;
        });

        await Task.WhenAll(t1, t2);
    }

在你的视图中,你应该有一些带有Button_OnClick和进度条命令的按钮:

<ProgressBar Maximum="100" Height="50" Value="{Binding TextProgress}"></ProgressBar>

还有一件事。看起来你有一个ViewModel,但你正在视图中工作。您应该将该逻辑移动到ViewModel。