首页 > 解决方案 > WPF中使用绑定的异步进度条

问题描述

我在可视化 MVVM WPF 进度条时遇到问题。我的主脚本方法运行但进度条根本没有更新。我可以使用提示来获得正确的方向。在我之前的代码中,我得到了使用技巧Progress<T>@Jonathan Willcock),但我无法成功实现它。

(请注意,这篇文章不是重复的问题,因为上次我使用了按钮单击,但我希望它纯粹在数据绑定上运行)

问题

如何将进度条异步绑定到视图模型中调用的方法?我正在使用委托命令来调用我的方法,并且我不想使用按钮单击事件。

我在视图中的内容 - XAML

我这里有两个主要功能,进度条和按钮。按钮成功启动方法调用,但进度条未加载。

    <ProgressBar Name="pbStatus"
                         Minimum="0"
                         Value="{Binding PrgBarVal, Mode=OneWay,UpdateSourceTrigger=PropertyChanged}"
                         Maximum="100"
                         Height="20"/>
    <Button x:Name = "ApplyButton" Margin="0 1 0 1" Content ="Run software" Command="{Binding RunCalcBtn, Mode=TwoWay}"/>

我在 XAML.cs 中有什么

我从后台工作人员方法中知道的是它尝试异步运行它。我在这里有一个问题,我在这里添加了一个断点来检查代码是否通过'Window_ContentRendered'方法运行,但它没有。

    public partial class UserInterface: UserControl
    {
        public UserInterface()
        {
            InitializeComponent();
        }
        private void Window_ContentRendered(object sender, EventArgs e)
        {
            BackgroundWorker worker = new BackgroundWorker();
            worker.WorkerReportsProgress = true;
            worker.DoWork += worker_DoWork; //Do I need a worker.ProgressChanged here?
            worker.RunWorkerAsync();
        }
        thenamespace.ViewModel.SelectedViewModel get = new thenamespace.ViewModel.SelectedViewModel ();
        void worker_DoWork(object sender, DoWorkEventArgs e)
        {

            for (int i = Convert.ToInt32(get.PrgBarVal); i < 100; i++)
            {
                (sender as BackgroundWorker).ReportProgress(i);
            }
        }
    }

我在视图模型中拥有的东西

在视图模型中,我使用委托命令来调用我的数据绑定方法。

public SelectedViewModel()Run()调用方法的地方。在该Run()方法中,其中的函数正确运行并正确更新了 的值PrgBarVal。但是,这根本不会更新进度条。

    public class SelectedViewModel : ModelView, INotifyPropertyChanged
    {
        public ModelView modelView { get; set; }

        private DelegateCommand _runCalcBtn;
        public DelegateCommand RunCalcBtn
        {
            get { return _runCalcBtn; }
            set
            {
                _runCalcBtn = value;
                SetPropertyChanged("RunCalcBtn"); //Same as RaisedPropertyChanged
            }
        }
        public SelectedViewModel()
        {
            modelView = new ModelView();
            RunCalcBtn = new DelegateCommand(Run);
        }

        private int _prgBarVal;
        public int PrgBarVal
        {
            get { return _prgBarVal; }
            set
            {
                _prgBarVal = value;
                OnPropertyChanged("PrgBarVal"); //Same as RaisedPropertyChanged
            }
        }

        //Main Function
        private async void Run()
        {

            MethodToWork(); //Function that calls other methods to run 
        }

非常感谢您的帮助!

标签: wpfasynchronousmvvmdata-bindingprogress-bar

解决方案


这是 ViewModel (使用NuGet ReactiveUI.WPF

public class MainViewModel : ReactiveObject
{
    private int _workProgress;

    public MainViewModel()
    {
        IProgress<int> progress = new Progress<int>( e => WorkProgress = e );
        StartWork = ReactiveCommand.CreateFromTask( () => ExecuteStartWorkAsync( progress ) );

    }

    private async Task ExecuteStartWorkAsync( IProgress<int> progress )
    {
        progress.Report( 0 );
        for ( int i = 0; i < 1000; i++ )
        {
            await Task.Delay( 10 ).ConfigureAwait( false );
            progress.Report( (int)Math.Floor( i / 1000.0 * 100.0 ) );
        }
    }


    public int WorkProgress { get => _workProgress; private set => this.RaiseAndSetIfChanged( ref _workProgress, value ); }
    public ICommand StartWork { get; }
}

和视图

<Window x:Class="WpfApp4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp4"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>
    <Grid>
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <Button Content="Start work" Command="{Binding StartWork}" Width="80"/>
            <ProgressBar Value="{Binding WorkProgress,Mode=OneWay}" Width="120"/>
        </StackPanel>
    </Grid>
</Window>

推荐阅读