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. Linux之grep命令详解

    简介 grep (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它 ...

  2. Create and Use Custom Attributes

    http://www.codeproject.com/Articles/1811/Creating-and-Using-Attributes-in-your-NET-applicat Create a ...

  3. Dynamics AX 2012 R2 安装 AIF IIS上的Web服务

    1.为什么使用IIS上的WEB服务 组件? 如果你要在Dynamics AX Service中使用HTTP Adapter,那么你就要安装IIS上的WEB服务 组件.HTTP Adapter会在IIS ...

  4. <Interview problem>二进制加法

    闲来无事,搜集一些有趣的面试题,以及解决方案,有些代码可能会自己写, 有些网上有比较完整的方案了,就直接把代码拷贝过来,描述一下解题思路. Given two binary strings, retu ...

  5. chrome表单自动填充去掉input黄色背景解决方案

    设置css代码如下: input:-webkit-autofill { -webkit-box-shadow: 0 0 0px 1000px white inset; } 参考文章:http://bl ...

  6. Auty自动化测试框架第二篇——读取与执行脚本列表

    [本文出自天外归云的博客园] 在Auty中的文件结构,lib目录下的read_selection.py和execute_selection.py文件:

  7. AES对称加密和解密

    package demo.security; import java.io.IOException; import java.io.UnsupportedEncodingException; impo ...

  8. JDBC读取新插入Oracle数据库Sequence值的5种方法

    Oracle的sequence实现非常灵活,所以也带来一些易用性问题,如何取到新插入记录生成的sequence值与其它数据库有较大差别,本文详国介绍了5种实现读取新插入记录sequence值的方法. ...

  9. Ubuntu+Win7双系统grub的修复问题

    最近,在grub引导的Ubuntu+Win7双系统上作业,用的是Ubuntu14.04.2.进行系统更新,更新到一般卡住了,恰好此时在进行grub相关文件的更新,我把机器重启后进入了grub resc ...

  10. Javascript学习笔记:9种创建对象的方式

    最基本的对象创建方式是通过Object构造函数或对象字面量的方式创建: ①通过Object构造函数的方式创建对象: var person=new Object();//或者写成var person={ ...