[WPF]MVVM Demo
最近一直搞Java,VS好久没有打开了,感觉有必要把以前.Net体系下一些经验给整理一下。现在越来越感觉,只会一门语言或者一种环境的开发,局限性会很大。下面先科普一下几种常用架构模式的发展过程吧:MVC - MVP - MVVM。MVC这个不用多说了,JAVA SSH框架下就是一种经典的MVC的应用了。关于MVP之前写过一个Asp.Net的MVP Demo有兴趣的朋友可以去参考一下:http://www.cnblogs.com/CopyPaster/archive/2011/01/10/1931705.html;现在再把MVVM补充一下吧。
MVVM的背景历史(以下内容是我对一些英文Blog部分内容的翻译,大家凑合读读吧)
自从人们开始用面向接口的方式开发软件,利用设计模式使之简化渐渐开始流行起来。例如:MVP模式在多样UI平台编程上的应用和流行。MVP模式是MVC模式提出后十年来的一种演变。如果你以前从未使用过MVP模式,这里有一个简单的解释:任何在屏幕上所能看到的被称之为View,视图中显示的数据称之为Model,View和Model之间通讯和联系由Presenter负责。视图依赖于Prensenter的数据处理逻辑,比如说:对于用户输入的响应,提供一个输入验证等。如果你深入了解MVP模式,建议去读Jean-Paul Boodhoo's的文章:http://msdn.microsoft.com/en-us/magazine/cc188690.aspx
2004年,Martin Fowler发表了一篇名为PM模式的文章。PM模式与MVP模式很类似,都将视图与其状态和行为相分离。PM模式中不同点是:在PM中创建了一个视图的抽象,于是视图的功能仅仅只是呈现PM。Fowler解释到:PM频繁更新视图,且两互相同步。由此可见,PM模式逻辑处理均以同步形式存在。
2005年,恰逢微软发布WPF和Silverlight,John Gossman,在他的博客提出了MVVM模式。MVVM模式和Fowler的PM模式一样均定义了视图状态和行为的抽象。Fowler介绍的PM模式是一种开发UI独立平台的方法。Gossman介绍的MVVM模式是一种充分利用WPF新特性创建用户接口的标准方法。换而言之,我认为MVVM是一种特殊的PM模式,是为WPF和Silverlight平台下的开发而量身打造的。
Demo说明:
Demo本身不包含什么业务逻辑,只是写了一些UI上的逻辑,主要的目的是展示MVVMDemo.SysFramwork.MVVM命名空间下核心代码,以及MVVM模式下的开发方式。Demo代码结构图如下:
Demo UI Xaml:
<Window x:Class="MVVMDemo.UI.View.TestWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mvvm="clr-namespace:MVVMDemo.SysFramwork.MVVM;assembly=MVVMDemo.SysFramwork" xmlns:common="clr-namespace:MVVMDemo.UI.Common" Title="TestWindow" Height="300" Width="500" Name="rootControl" > <Window.Resources> <ResourceDictionary> <Style x:Key="PaymentInputTextBoxStyle" TargetType="TextBox"> <Setter Property="mvvm:CommandSource.Trigger"> <Setter.Value> <mvvm:CommandTriggerGroup> <mvvm:EventCommandTrigger RoutedEvent="FrameworkElement.Loaded" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TextBox}}}" Command="{Binding ElementName=rootControl, Path=DataContext.PaymentInputTextBoxLoadCommand}"/> <mvvm:EventCommandTrigger RoutedEvent="TextBox.GotFocus" Command="{Binding ElementName=rootControl, Path=DataContext.PaymentInputTextBoxGotFocusCommand}"/> <mvvm:EventCommandTrigger RoutedEvent="TextBox.GotMouseCapture" Command="{Binding ElementName=rootControl, Path=DataContext.PaymentInputTextBoxGotFocusCommand}"/> <mvvm:EventCommandTrigger RoutedEvent="TextBox.KeyDown" Command="{Binding ElementName=rootControl, Path=DataContext.PaymentInputTextBoxKeyDownCommand}"/> </mvvm:CommandTriggerGroup> </Setter.Value> </Setter> </Style> </ResourceDictionary> </Window.Resources> <DockPanel Margin="10,50,10,10"> <Grid DockPanel.Dock="Top" Margin="5,5,5,5"> <Grid.RowDefinitions> <RowDefinition Height="30" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition /> </Grid.ColumnDefinitions> <TextBlock Text="需要支付:" /> <TextBox Grid.Column="1" Name="tbRequiredAmount" Height="25" HorizontalAlignment="Stretch" common:TextBoxMaskBehavior.Mask="Decimal" Text="{Binding Path=RequiredAmount, UpdateSourceTrigger=PropertyChanged}"/> </Grid> <Grid DockPanel.Dock="Top" Margin="5,5,5,5" KeyboardNavigation.TabNavigation="Cycle"> <Grid.RowDefinitions> <RowDefinition Height="30" /> <RowDefinition Height="30" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition /> <ColumnDefinition Width="Auto"/> <ColumnDefinition /> </Grid.ColumnDefinitions> <TextBlock Text="现金:" /> <TextBox Grid.Column="1" Name="textBoxCash" TabIndex="1" Height="25" HorizontalAlignment="Stretch" Style="{StaticResource PaymentInputTextBoxStyle}" common:TextBoxMaskBehavior.Mask="Decimal" Tag="{Binding PaymentTypeCashRcd}" Text="{Binding Path=CashierAmount, UpdateSourceTrigger=PropertyChanged}" /> <TextBlock Grid.Column="2" Text="信用卡:" /> <TextBox Grid.Column="3" Name="textBoxCreditCard" TabIndex="2" Height="25" HorizontalAlignment="Stretch" Style="{StaticResource PaymentInputTextBoxStyle}" common:TextBoxMaskBehavior.Mask="Decimal" Tag="{Binding PaymentTypeCreditCardRcd}" Text="{Binding Path=CreditCardAmount, UpdateSourceTrigger=PropertyChanged}"/> <TextBlock Grid.Row="1" Text="支票:" /> <TextBox Grid.Column="1" Grid.Row="1" Name="textBoxCheck" TabIndex="3" Height="25" HorizontalAlignment="Stretch" Style="{StaticResource PaymentInputTextBoxStyle}" common:TextBoxMaskBehavior.Mask="Decimal" Tag="{Binding PaymentTypeCheckRcd}" Text="{Binding Path=CheckAmount, UpdateSourceTrigger=PropertyChanged}" /> <TextBlock Grid.Column="2" Grid.Row="1" Text="保险:" /> <TextBox Grid.Column="3" Grid.Row="1" Name="textBoxInsuranceCard" TabIndex="4" Height="25" HorizontalAlignment="Stretch" Style="{StaticResource PaymentInputTextBoxStyle}" common:TextBoxMaskBehavior.Mask="Decimal" Tag="{Binding PaymentTypeInsuranceCardRcd}" Text="{Binding Path=InsuranceCardAmount, UpdateSourceTrigger=PropertyChanged}" /> </Grid> <DockPanel DockPanel.Dock="Bottom" LastChildFill="False"> <Button Name="buttonConfirm" DockPanel.Dock="Right" Height="30" Width="75" Content="确认" IsEnabled="{Binding IsReadyToSubmit}" Command="{Binding Path=ButtonConfirmCommand}"> <mvvm:CommandSource.Trigger> <mvvm:CommandTriggerGroup> <mvvm:EventCommandTrigger RoutedEvent="FrameworkElement.Loaded" CommandParameter="{Binding ElementName=buttonConfirm}" Command="{Binding ElementName=rootControl, Path=DataContext.ConfirmButtonLoadCommand}"/> </mvvm:CommandTriggerGroup> </mvvm:CommandSource.Trigger> </Button> <Button Name="buttonCancel" DockPanel.Dock="Right" Height="30" Width="75" Content="取消" CommandParameter="{Binding ElementName=rootControl}" Command="{Binding Path=ButtonCancelCommand}"/> </DockPanel> </DockPanel> </Window>
Demo下载地址: