【问题标题】:How to implement a progress bar using the MVVM pattern如何使用 MVVM 模式实现进度条
【发布时间】:2011-04-01 00:37:19
【问题描述】:

我有一个基于 MVVM 设计模式的 WPF 应用程序。

我希望在应用中实现一个进度条,遵循 MVVM 模式。

有人对如何实现这一点有任何建议吗?

提前致谢

【问题讨论】:

    标签: c# wpf mvvm


    【解决方案1】:

    通常,您的 UI 会简单地绑定到 VM 中的属性:

    <ProgressBar Value="{Binding CurrentProgress, Mode=OneWay}" 
                 Visibility="{Binding ProgressVisibility}"/>
    

    您的 VM 将使用 BackgroundWorker 在后台线程上执行工作,并定期更新 CurrentProgress 值。像这样的:

    public class MyViewModel : ViewModel
    {
        private readonly BackgroundWorker worker;
        private readonly ICommand instigateWorkCommand;
        private int currentProgress;
    
        public MyViewModel()
        {
            this.instigateWorkCommand = 
                    new DelegateCommand(o => this.worker.RunWorkerAsync(), 
                                        o => !this.worker.IsBusy);
    
            this.worker = new BackgroundWorker();
            this.worker.DoWork += this.DoWork;
            this.worker.ProgressChanged += this.ProgressChanged;
        }
    
        // your UI binds to this command in order to kick off the work
        public ICommand InstigateWorkCommand
        {
            get { return this.instigateWorkCommand; }
        }
    
        public int CurrentProgress
        {
            get { return this.currentProgress; }
            private set
            {
                if (this.currentProgress != value)
                {
                    this.currentProgress = value;
                    this.OnPropertyChanged(() => this.CurrentProgress);
                }
            }
        }
    
        private void DoWork(object sender, DoWorkEventArgs e)
        {
            // do time-consuming work here, calling ReportProgress as and when you can
        }
    
        private void ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.CurrentProgress = e.ProgressPercentage;
        }
    }
    

    【讨论】:

    • 嗨,Kent,我需要一个单独的模型和视图模型用于进度条吗?或者我会在我打算使用它的每个现有视图中添加一个进度条吗?
    • 我会从每个视图使用一个简单开始,然后决定是否可以将其抽象为可重用组件。
    • 谢谢,非常有用的例子!我刚刚在测试期间发现的两件事值得注意:1)CurrentProgress 的设置器必须是公共的,或者必须在进度条上明确指定OneWay 模式绑定。默认值似乎是 TwoWay(对于 Progressbar 来说很奇怪),因此绑定引擎使用私有设置器抛出异常。 2) 使用ReportProgress 时,似乎有必要将BackgroundWorkerWorkerReportsProgress 属性设置为true。否则线程执行静默停止(无异常,仅在RunWorkerCompleted事件参数中可见)。
    • @Kent Boogaart,写完这样的字符串后:" this.instigateWorkCommand = new DelegateCommand(o => this.worker.RunWorkerAsync, o => !this.worker.IsBusy);" . VS2010 抛出错误:“delegate 'system.action' 不接受 1 个参数”。你能告诉我如何克服它吗?
    • @KentBoogaart,在写了这样的字符串之后:" this.instigateWorkCommand = new DelegateCommand(o => this.worker.RunWorkerAsync, o => !this.worker.IsBusy);" . VS2010 抛出错误:“delegate 'system.action' 不接受 1 个参数”。你能告诉我如何克服它吗?
    【解决方案2】:

    使用ProgressBar 控件并将其Value 属性绑定到ViewModel 的属性:

    查看

    <ProgressBar Minimum="0" Maximum="0" Value="{Binding CurrentProgress}" />
    

    视图模型

    private double _currentProgress;
    public double CurrentProgress
    {
        get { return _currentProgress; }
        private set
        {
            _currentProgress = value;
            OnPropertyChanged("CurrentProgress");
        }
    }
    

    【讨论】:

    • 如何将它与我的命令连接起来?也就是说,我有一个按钮,点击后,我想启动进度条,直到操作完成。
    • @KalaJ,您只需要在您的操作中更新 CurrentProgress 属性(例如,如果它是一个循环,则在每次迭代时更新值)
    • 问题是当我将 CD 插入计算机时,我只是在等待系统读取/检测 CD。有时系统需要一段时间才能读取 CD,而有时则不需要。如何更新这样的值?我在想也许使用不确定的进度条,但我仍然对如何将它连接到我的命令感到困惑?
    • @KalaJ,在这种情况下,您无法显示真正的进度,因为您不知道该操作有多接近完成。您可以在 XAML 中将 IsIndeterminate 设置为 true,并在 ViewModel 中使用 bool 属性来隐藏/显示进度条。
    • 好的,在这种情况下,我需要一个 value 属性吗?
    【解决方案3】:

    向您的虚拟机添加两个属性:

    bool IsProgressBarVisible
    double ProgressValue
    

    如果您在 VM 中启动长时间操作,请将 IsProgressBarVisible-property 设置为 true,并将 ProgressValue periodical 设置为当前进度值。尝试计算 0 到 100 之间的值。这样做的好处是您不必提供最小值和最大值。 异步操作完成后,将 IsProgressBarVisible 设置为 false。

    在 XAML 中,绑定到这两个属性。使用值转换器将布尔可见性转换为可见性。

    <ProgressBar Value="{Binding ProgressValue}" Visibility="{Binding IsProgressBarVisible,Converter={StaticResource BooleanToVisibility_ValueConverter}}"/> 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-16
      相关资源
      最近更新 更多