WPF技术的主要特点是数据驱动UI,所以在使用WPF技术开发的过程中是以数据为核心的,WPF提供了数据绑定机制,当数据发生变化时,WPF会自动发出通知去更新UI。

恰当的模式可以让我们轻松达到“高内聚低耦合”,MVVM就是为WPF量身定做的,该模式充分利用了WPF的数据绑定机制,最大限度地降低了XAML和CS文件的耦合度,即UI显示和逻辑代码的耦合度,如需更换界面时,逻辑代码修改很少,甚至不用修改。与WinForm开发相比,我们一般在后置代码中会使用控件的名字来操作控件的属性来更新UI,而在WPF中通常是数据绑定来更新UI。在响应用户操作上,WinForm是通过控件的事件来处理,而WPF可以使用命令绑定的方式来处理,耦合度将降低。

我们可以通过下图来理解MVVM模式:

  View,UI界面,即XAML实现的页面,负责与用户交互,接收用户输入,把数据展现给用户。

  ViewModel,一个C# 类,是View的抽象,负责收集需要绑定的数据和命令,帮助View和Model之间的信息转换,将View的Command传送到Model,聚合Model对象,通过View类的DataContent属性绑定到View,同时也可以处理一些UI逻辑。

  Model,数据访问层,就是系统中的对象,可包含属性和行为。

  一般,View对应一个ViewModel,ViewModel可以聚合N个Model,ViewModel可以对应多个View,Model不知道View和ViewModel的存在。

  View与ViewModel连接可通过下面的方式

  (1)Binding Data:实现数据的传递;

  (2)Command:实现操作的调用;

  (3)AttachBehavior:实现控件加载过程中的操作;

示例讲解

一、Model

    class ButtonInfo
{
public string Content { get; set; }
}

ButtonInfo

    class DownLoadFileInfo
{
public string url = "";
public string fileName = ""; public DownLoadFileInfo(string _url, string _fileName)
{
url = _url;
fileName = _fileName;
}
}

DownLoadFileInfo

    class ProgressBarInfo
{
public long pbCurrentMaxLength { get; set; }
public long pbCurrentLength { get; set; }
public long pbTotalMaxLength { get; set; }
public long pbTotalLength { get; set; }
public ProgressBarInfo()
{ }
public ProgressBarInfo(long pbCurrentMaxLength, long pbCurrentLength, long pbTotalMaxLength, long pbTotalLength)
{
this.pbCurrentMaxLength = pbCurrentMaxLength;
this.pbCurrentLength = pbCurrentLength;
this.pbTotalLength = pbTotalLength;
this.pbTotalMaxLength = pbTotalMaxLength;
}
}

ProgressBarInfo

二、View

<Window x:Class="AutoUpdate_MVVM.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="201" Width="505">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="GESBrushes.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid Background="{StaticResource SolidBrushBackground}">
<Button Content="{Binding Button.Content,Mode=TwoWay}" Command="{Binding Pause}" Name="btnPause" HorizontalAlignment="Left" Margin="108,113,0,0" VerticalAlignment="Top" Width="75"/>
<Button Content="关闭" Command="{Binding Close}" Name="btnClose" HorizontalAlignment="Left" Margin="251,113,0,0" VerticalAlignment="Top" Width="75" />
<ProgressBar Value="{Binding ProgressBar.pbCurrentLength,Mode=TwoWay}" Maximum="{Binding ProgressBar.pbCurrentMaxLength}" Name="pbCurrent" HorizontalAlignment="Left" Height="16" Margin="90,32,0,0" VerticalAlignment="Top" Width="355"/>
<ProgressBar Value="{Binding ProgressBar.pbTotalLength,Mode=TwoWay}" Maximum="{Binding ProgressBar.pbTotalMaxLength}" Name="pbTotal" HorizontalAlignment="Left" Height="16" Margin="90,65,0,0" VerticalAlignment="Top" Width="355"/>
<Label Content="当前进度:" Foreground="{StaticResource SolidBrushForeground}" Height="28" HorizontalAlignment="Left" Margin="25,25,0,0" Name="label1" VerticalAlignment="Top" FontWeight="Normal" FontStyle="Normal" FontStretch="{Binding}" />
<Label Content="总 进 度:" Foreground="{StaticResource SolidBrushForeground}" Height="28" HorizontalAlignment="Left" Margin="25,59,0,0" Name="label2" VerticalAlignment="Top" />
</Grid>
</Window>

MainWindow.xaml

    public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new DownLoadFile();
}
}

MainWindow.xaml.cs

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="SolidBrushBackground" Color="#FF3A9692"/>
</ResourceDictionary>

GESBrushes.xaml

三、ViewModel

(1)DownLoadFile类,一个实现INotifyPropertyChanged接口的类,目的是绑定数据属性。WPF中实现这个接口的类的属性成员才具有通知UI的能力。

    class DownLoadFile : INotifyPropertyChanged,IDisposable
{
public event PropertyChangedEventHandler PropertyChanged; #region [Object] ManualResetEvent _pauseEvent = new ManualResetEvent(true);
List<DownLoadFileInfo> _listFileInfo = new List<DownLoadFileInfo>();
List<string> _listUrl = new List<string>(); readonly int MAX_BUFFER_SIZE = ; long totalCurrentLength = ;
long totalLength = ; ProgressBarInfo _ProgressBarInfo;
ButtonInfo _ButtonInfo;
HttpWebRequest myrq;
HttpWebResponse myrp; #endregion #region [Property] public bool IsFinish { get; set; } private ProgressBarInfo _ProgressBar;
public ProgressBarInfo ProgressBar
{
get
{
return _ProgressBar;
}
set
{
_ProgressBar = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("ProgressBar"));
;
}
}
} private ButtonInfo _Button;
public ButtonInfo Button
{
get { return _Button; }
set
{
_Button = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Button"));
}
}
} public ICommand Pause
{
get
{
return new PauseCommand(this);
}
} public ICommand Close
{
get
{
return new CloseCommand(this);
}
} #endregion #region DownLoadFile
public DownLoadFile()
{
_ProgressBarInfo = new ProgressBarInfo();
_ButtonInfo = new ButtonInfo();
_ButtonInfo.Content = "暂停";
Button = _ButtonInfo; //注意此次的赋值 _listUrl.Add(@"http://127.0.0.1/孙晓林周报(2014-12-11)1.txt");
_listUrl.Add(@"http://127.0.0.1/孙晓林周报(2014-12-11)2.txt"); for (int i = ; i < _listUrl.Count; i++)
{
string url = _listUrl[i];
string[] fileNames = url.Split('/');
if (fileNames.Length > )
{
string fileName = fileNames[fileNames.Length - ];
string fileFullName = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\" + fileName;//文件保存路径 DownLoadFileInfo fileInfo = new DownLoadFileInfo(_listUrl[i], fileFullName);
_listFileInfo.Add(fileInfo);
}
} for (int i = ; i < _listFileInfo.Count; i++)
{
HttpWebRequest myrq = (HttpWebRequest)HttpWebRequest.Create(_listFileInfo[i].url);
HttpWebResponse myrp = (HttpWebResponse)myrq.GetResponse();
totalLength += myrp.ContentLength;
}
//下载文件
Thread newThread = new Thread(new ThreadStart(PerformDownloading));
newThread.Start(); }
#endregion #region PerformDownloading
/// <summary>
/// 下载文件
/// </summary>
private void PerformDownloading()
{
try
{
if (_listFileInfo != null)
{
for (int i = ; i < _listFileInfo.Count; i++)
{
string url = _listFileInfo[i].url;
string fileName = _listFileInfo[i].fileName;
_ProgressBarInfo.pbCurrentLength = ;
//System.Net.ServicePointManager.DefaultConnectionLimit = 50;
System.GC.Collect();
myrq = (HttpWebRequest)HttpWebRequest.Create(url);
myrq.KeepAlive = false;
myrp = (HttpWebResponse)myrq.GetResponse(); _ProgressBarInfo.pbCurrentMaxLength = myrp.ContentLength;
_ProgressBarInfo.pbTotalMaxLength = totalLength; System.IO.Stream st = myrp.GetResponseStream();
System.IO.Stream so = new System.IO.FileStream(fileName, System.IO.FileMode.Create);
long totalDownloadedByte = ; byte[] buffer = new byte[MAX_BUFFER_SIZE];
int osize = ; while (true)
{
_pauseEvent.WaitOne();//阻止当前线程,直到当前 WaitHandle 收到信号。
osize = st.Read(buffer, , MAX_BUFFER_SIZE);
totalDownloadedByte += osize;
totalCurrentLength += osize;
_ProgressBarInfo.pbCurrentLength = totalDownloadedByte;
_ProgressBarInfo.pbTotalLength = totalCurrentLength;
ProgressBar = _ProgressBarInfo;
Thread.Sleep();
if (osize == )
{
break;
}
so.Write(buffer, , osize);
}
so.Close();
st.Close(); CloseHttpWebObject();
}
IsFinish = true;
}
}
catch (System.Exception ex)
{
MessageBox.Show(ex.Message);
}
}
#endregion #region PauseDownLoad
public void PauseDownLoad()
{ if (Button.Content == "暂停")
{
_ButtonInfo.Content = "继续";
Button = _ButtonInfo;
_pauseEvent.Reset();
}
else
{
_ButtonInfo.Content = "暂停";
Button = _ButtonInfo;
_pauseEvent.Set();
}
}
#endregion #region IDisposable 成员 public void Dispose()
{
_pauseEvent.Close();//释放由当前 WaitHandle 持有的所有资源。 for (int i = ; i < _listFileInfo.Count; i++)
{
_listFileInfo[i] = null;
}
CloseHttpWebObject();
Application.Current.Shutdown();
} private void CloseHttpWebObject()
{
if (myrq != null)
{
myrq.Abort();
}
if (myrp != null)
{
myrp.Close();
}
} #endregion
}

(2)CloseCommand类和PauseCommand类,实现ICommand接口的类,目的是绑定命令属性。WPF中实现ICommand接口的类才能作为命令绑定到UI。

 class CloseCommand:ICommand
{
private DownLoadFile _DownLoadFile;
public CloseCommand(DownLoadFile downLoadFile)
{
_DownLoadFile = downLoadFile;
}
#region Achieve Items
public bool CanExecute(object parameter)//定义用于确定此命令是否可以在当前状态下执行的方法,如果可以执行此命令,返回true,否则返回false。
{
return true;
} public event EventHandler CanExecuteChanged;//当出现影响是否执行该命令的更改时发生 public void Execute(object parameter)//定义在调用此命令时调用的方法
{
_DownLoadFile.Dispose();
}
#endregion
}

CloseCommand

 class PauseCommand : ICommand
{
private DownLoadFile _DownLoadFile;
public PauseCommand(DownLoadFile downLoadFile)
{
_DownLoadFile = downLoadFile;
}
public bool CanExecute(object parameter)
{
if (_DownLoadFile.IsFinish)
{
return false;
}
else
{
return true;
}
} public event EventHandler CanExecuteChanged; public void Execute(object parameter)
{
_DownLoadFile.PauseDownLoad();
}
}

PauseCommand

二、

WPF之MVVM模式讲解的更多相关文章

  1. 【WPF】MVVM模式的3种command

    原文:[WPF]MVVM模式的3种command 1.DelegateCommand 2.RelayCommand 3.AttachbehaviorCommand 因为MVVM模式适合于WPF和SL, ...

  2. 【转】【WPF】MVVM模式的3种command

    1.DelegateCommand 2.RelayCommand 3.AttachbehaviorCommand 因为MVVM模式适合于WPF和SL,所以这3种模式中也有一些小差异,比如RelayCo ...

  3. WPF之MVVM模式(2)

    我们都想追求完美 Every view in the app has an empty codebehind file, except for the standard boilerplate cod ...

  4. WPF之MVVM模式(1)

    MVVM模式 一.MVVM模式概述 MVVM Pattern : Model\View\ViewModel View:视图.UI界面 ViewModel:ViewModel是对Model的封装,通过一 ...

  5. WPF中MVVM模式的 Event 处理

    WPF的有些UI元素有Command属性可以直接实现绑定,如Button 但是很多Event的触发如何绑定到ViewModel中的Command呢? 答案就是使用EventTrigger可以实现. 继 ...

  6. WPF之MVVM模式(3)

    有种想写一个MVVM框架的冲动!!! 1.Model中的属性应不应该支持OnPropertyChanged事件? 不应该.应该有ViewModel对该属性进行封装,由ViewModel提供OnProp ...

  7. WPF中 MVVM模式的Slider Binding.

    对于Button的Command的绑定可以通过实现ICommand接口来进行,但是Slider并没有Command属性. 另外如果要实现MVVM模式的话,需要将一些Method和Slider的Even ...

  8. WPF采用MVVM模式(绑定:纯前台、命令:触发器绑定命令)

    MVVM绑定 view-viewModel-model,模型介绍省略,就是创建类,添加字段封装属性.注:控件的绑定只能绑定到属性上,不能绑定到字段上: 接下来就是代码 (view): <Wind ...

  9. WPF中MVVM模式下控件自有的事件绑定

    1.原因 在WPF中单纯的命令绑定往往不能满足覆盖所有的事件,例如ComboBox的SelectionChanged事件,DataGrid的SelectionChanged事件等等,这时就可以用事件绑 ...

随机推荐

  1. iOS中UIWebView与其中网页的javascript的交互

    首发:个人博客,更新&纠错&回复 1.本地语言调js的方式与android中的方式类似,也是向WebView控件发送要调用的js语句 2. 但js调本地语言,则不是像android那样 ...

  2. es5.0安装问题

    ES的5.0版本听说在性能上大大优化,于是老大说准备换5.0版本.由于在技术群看到很多人都说ES 5.0 安装有问题,在这里贴出自己在使用最新版5.0遇到的问题和解决方法 1.Elasticsearc ...

  3. Dynamics AX 2012 R2 配置E-Mail模板

    在AX中使用邮件模板可以,可以让邮件的内容更专业化.下面,跟随Reinhard一起,配置E-Mail模板吧. 进入Organization Administration>Setup>E-m ...

  4. Linux WordPress博客的安装

    1:新建文件夹

  5. shiro的Helloworld

    package shiro; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.UsernamePassword ...

  6. Delphi名站以及高手Blog

    以前知道的: http://cnblogs.com/del (万一兄的,这个不用解释了) http://www.cnblogs.com/del/archive/2010/04/25/1720750.h ...

  7. iOS 解惑

    (1)ARC下IBOutlet用weak还是strong http://blog.csdn.net/yongyinmg/article/details/20623605 苹果也没有完全建议用weak ...

  8. 临时文件相关的v$tempfile v$sort_usage与V$tempseg_usage

    SQL> select username,user,segtype,segfile#,segblk#,extents,segrfno# from v$sort_usage; SEGFILE#代表 ...

  9. 【bzoj1084】最大子矩阵

    题意 这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大.注意:选出的k个子矩阵不能相互重叠. \(1≤n≤100,1≤m≤2,1≤k≤10\) 分析 由于\(m\)只有两 ...

  10. null和undefined

    null表示"没有对象",即该处不应该有值.典型用法是: (1) 作为函数的参数,表示该函数的参数不是对象. (2) 作为对象原型链的终点. undefined表示"缺少 ...