简体   繁体   English

在 WPF C# MVVM 中使用进度条

[英]Using progress bar in WPF C# MVVM

My goal is to update the progress bar while another set of script (calculations) is running.我的目标是在另一组脚本(计算)运行时更新进度条。

I have followed the sample files from here and tried to bind it to my MVVM script but the progress bar would not update.我遵循了此处的示例文件并尝试将其绑定到我的 MVVM 脚本,但进度条不会更新。

在此处输入图片说明

Here is the Progressbar script这是进度条脚本

In the script below, I have included progressBarCounter and noOfData as a value in another script that is calculated in a method.在下面的脚本中,我将progressBarCounternoOfData作为值包含在另一个脚本中,该值是在方法中计算的。

Proof that data is updated数据更新的证明

在此处输入图片说明

public partial class ProgressBarTaskOnWorkerThread : Window
{
    public ProgressBarTaskOnWorkerThread()
    {
        InitializeComponent();
    }

    private void Window_ContentRendered(object sender, EventArgs e)
    {
        BackgroundWorker worker = new BackgroundWorker();
        worker.WorkerReportsProgress = true;
        worker.DoWork += worker_DoWork;
        worker.ProgressChanged += worker_ProgressChanged;

        worker.RunWorkerAsync();
    }

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        EtabsDataFormatting.ViewModel.SpliceViewModel data = new EtabsDataFormatting.ViewModel.SpliceViewModel();

        for (int i = data.progressBarCounter; i < data.noOfData;)
        {
            (sender as BackgroundWorker).ReportProgress(i);
        }
    }

    void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        pbStatus.Value = e.ProgressPercentage;
        int perc = Convert.ToInt32(pbStatus.Value);
        UpdateProgress(perc);
    }

    public void UpdateProgress(int percentage)
    {
        pbStatus.Value = percentage;
        if (percentage == 100)
        {
            Close();
        }
    }
}

Here is part of my XAML code for the button to start calculations and run the progressbar这是我的 XAML 代码的一部分,用于开始计算和运行进度条的按钮

The command Binding = RunCalcBtn is bound to the calculation scripts, therefore, I have created a click to run the progress bar instead.命令 Binding = RunCalcBtn 绑定到计算脚本,因此,我创建了一个单击来运行进度条。

<Button x:Name = "ApplyButton" Margin="0 1 0 1" Content ="Start Calculation" Command="{Binding RunCalcBtn, Mode=TwoWay}" Click ="PrgBar_Click"/>

Progressbar XAML.cs button click Progressbar XAML.cs 按钮单击

This part displays the progress bar, but it does not update.这部分显示进度条,但不更新。

private void PrgBar_Click(object sender, RoutedEventArgs e)
{
    ProgressBar.ProgressBarTaskOnWorkerThread progressWindow = new ProgressBar.ProgressBarTaskOnWorkerThread();
    progressWindow.Show();
}

Thank you so much for helping me in advance!非常感谢您提前帮助我!

As Flithor has said, the best way to achieve this is with Progress<T> .正如 Flithor 所说,实现这一目标的最佳方法是使用Progress<T>

I give a short illustration of how to use this.我简要说明了如何使用它。

Firstly you need to create a Property in your View Model so that you can bind the ProgressBar's Value to something.首先,您需要在您的视图模型中创建一个Property ,以便您可以将 ProgressBar 的值绑定到某个东西。 Your ViewModel will need to implement INotifyPropertyChanged so that the Property set can invoke RaisePropertyChangedEvent .您的 ViewModel 将需要实现INotifyPropertyChanged以便属性set可以调用RaisePropertyChangedEvent

Next create a Progress inside the method called by the Button click and pass it to your worker method.接下来在按钮单击调用的方法中创建一个 Progress 并将其传递给您的工作方法。 Use an ICommand for this, so that it can be bound to your Button (you don't need the Click event).为此使用 ICommand,以便它可以绑定到您的 Button(您不需要 Click 事件)。 Something like this:像这样的东西:

var progress = new Progress<int>(percent =>
    {
        ProgressProperty = percent;
    });

await Task.Run(() => myWorker(progress));

Finally within your worker method you periodically update the value like this:最后,在您的工作方法中,您会定期更新值,如下所示:

private void myWorker(IProgress<int> progress)
{
    progress.Report(1);
    // ...
    progress.Report(100);
}

By way of explanation: I used an integer, but you can also use a double if you want really fine calculations!说明一下:我使用的是整数,但如果您想要真正精细的计算,也可以使用双精度数! The constructor of the Progress object takes the ProgressProperty (the name I gave to the property that gets bound to the ProgressBar) as a parameter. Progress 对象的构造函数采用 ProgressProperty(我给绑定到 ProgressBar 的属性的名称)作为参数。 This means that when the worker calls Report(), the ProgressProperty is automatically updated with the new value, and hence can be reflected in the UI.这意味着当工作人员调用 Report() 时,ProgressProperty 会自动更新为新值,因此可以反映在 UI 中。 Finally your worker method is invoked with await so that the UI is able to update on every incremented value.最后使用 await 调用您的工作方法,以便 UI 能够更新每个递增的值。

For a very full explanation on Progress, see Stephen Cleary's blog有关 Progress 的完整说明,请参阅 Stephen Cleary 的博客

In MVVM WPF , you should do this to take full advantage of it:MVVM WPF 中,您应该这样做以充分利用它:

View:看法:

<Grid>
   <ProgressBar Name="myProgressBar"
                Minimum="0" 
                Value="{Binding ProgressBarValue,Mode=OneWay,UpdateSourceTrigger=PropertyChanged}" 
                Maximum="100"
                Foreground="{Binding ColorState,Mode=OneWay,UpdateSourceTrigger=PropertyChanged}"
                Background="#424242"
                BorderBrush="Transparent"
                BorderThickness="0"/>
   <TextBlock Text="{Binding ElementName=myProgressBar, Path=Value,Mode=OneWay,UpdateSourceTrigger=PropertyChanged, StringFormat={}{0:0}%}" 
              FontWeight="DemiBold"
              HorizontalAlignment="Center"
              VerticalAlignment="Center" />
</Grid>

ViewModel:视图模型:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Threading;

namespace YourNameSpace.Models
{
    public class Device : INotifyPropertyChanged
    {
        public Device()
        {
            this.ProgressBarValue = 50; // Your ProgressBar Foreground will be "GREEN" automatically
                                        // This is the 
        }
        
        private double progressBarValue;
        public double ProgressBarValue
        {
            get { return progressBarValue; }
            set 
            { 
                progressBarValue = value; 
                if(progressBarValue < 50)
                    this.ColorState = "Red";
                else if (progressBarValue >= 50)
                    this.ColorState = "Green";
                NotifyPropertyChanged("ProgressBarValue"); 
            }
        }
        private string colorState = "Transparent";
        public string ColorState
        {
            get { return colorState; }
            set { colorState = value; NotifyPropertyChanged("ColorState"); }
        }
        
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(string Obj)
        {
            if (PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(Obj));
            }
        }
    }
}

You can REMOVE this from your code:您可以从代码中删除它:

    void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        pbStatus.Value = e.ProgressPercentage;
        int perc = Convert.ToInt32(pbStatus.Value);
        UpdateProgress(perc);
    }

    public void UpdateProgress(int percentage)
    {
        pbStatus.Value = percentage;
        if (percentage == 100)
        {
            Close();
        }
    }

And ONLY use this:并且使用这个:

for (int i = data.progressBarCounter; i < 100; i++)
{
    ProgressBarValue = i;
}

Your您的

ProgressBar Value进度条值

Progress Foreground Color进度前景色

will be updated automatically .自动更新。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM