MVVM中轻松控制ProgressBar

来源:互联网 发布:苹果茶软件 编辑:程序博客网 时间:2024/05/19 19:58
MVVM中要控制进度条其实很方便,但是在开始之前我们要解决一个线程问题。
首先WPF的应用程序至少有连个线程,一个是管理UI的线程,一个是绘制UI的线程。我们需要实现类似复制进度的完成率显示,复制线程不能和UI线程相同,否则顾此失彼。一定要创建一个新线程执行操作。通常我们使用Thread类来实现,这次我使用了线程池ThreadPool来实现。

见截图:


窗体代码(窗体上加三个控件ProgressBar+TextBlock+Button):
<Window x:Class="ProgressDemo.MainWindow"        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:vm="clr-namespace:ProgressDemo"        Title="MainWindow" MinHeight="117" MinWidth="290" MaxHeight="117" Width="441"><Window.DataContext><vm:MainWindowViewModel /></Window.DataContext>    <Grid><ProgressBar Height="22" Margin="20,12,12,0" VerticalAlignment="Top"  Value="{Binding Schedule}"/><TextBlock Height="23" HorizontalAlignment="Left" Margin="20,43,0,0" VerticalAlignment="Top"    Text="{Binding Message}"/><Button Content="Start" Height="23" Margin="0,43,12,0" Name="button1" VerticalAlignment="Top" HorizontalAlignment="Right" Width="75"Command="{Binding CopyCommand}"/></Grid></Window>

ViewModel代码:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ComponentModel;using System.Windows.Input;using Microsoft.Practices.Prism.Commands;using System.Threading;namespace ProgressDemo {public class MainWindowViewModel:INotifyPropertyChanged {public event PropertyChangedEventHandler PropertyChanged;private double _schedule;///<summary>///进度百分比///</summary>public double Schedule {get { return _schedule; }set {if (_schedule != value) {_schedule = value;if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Schedule"));}}}private string _message;///<summary>///显示的消息///</summary>public string Message {get { return _message; }set {if (_message != value) {_message = value;if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Message"));}}}/// <summary>/// 模拟复制命令/// </summary>public ICommand CopyCommand {get {return new DelegateCommand(() => {Random random = new Random();int count = random.Next(5000, 10000);//使用线程池执行ThreadPool.QueueUserWorkItem(new WaitCallback(obj => {for (int i = 1; i <= count; i++) {/* * 更新: * 1.完成进度的百分比 * 2.消息文字 * 3.按钮的状态 */Schedule = i * 100.0 / count;Message = string.Format("{0:0.0}% completed.", Schedule);if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("CopyCommand"));Thread.Sleep(1);}}));},()=>{//返回按钮状态是否CanExcutereturn Schedule == 0 || Schedule == 100;});}}}}


注意:
1.ViewModel实现了INotifyPropertyChanged接口,目的通知View数据的更改;
2.CopyCommand是模拟了复制大文件的操作,先创建了一个随机数,相当于文件的大小,然后用循环模拟复制进度。
ThreadPool.QueueUserWorkItem是执行线程池操作,并执行new WaitCallBack中的委托,此处我采用Lambda委托方式,直接将委托的方法代码写在回调函数中,这样的好处是能直接使用变量count,而不需要再传递到方法中;方法中还使用了Thread.Sleep(1),让线程池中的线程暂停1ms,目的不让程序跑得太快。每一次操作中,还更新了两个控件的显示内容,以及按钮的可用状态。
3.DelegateCommand是Prism中的类,需要引用Microsoft.Practices.Prism.dll

原创粉丝点击