WPF之MVVM解析

我们前面一节白话白眼,都只是从概念上了解了mvvm,了解和做还是差距很大,所以我们同样需要亲自动手实验来真的弄懂mvvm。
例子就取一个生活中的,用mvvm模式完成家庭的操作,比如显示查询家庭成员,增加家庭成员(娶妻生子等),减少家庭成员(嫁女老去等).
  确定好这个例子我们就需要先准备一下数据,我们首先想到可能是用数据库,不过silverlight是浏览器客户端的东西,是不能和你以前使用asp.net一样主动直接连接数据库的,如果你真的要开始就连接数据库,你还得准备另外学习一些知识。
我们先构思一下自己的类的样子:
[csharp] view plain copy print ?
  1. class familymember 
  2.          { 
  3.               public string Name{get,set;}//姓名 
  4.               public string Sex{get,set;}//性别(不使用bool,因为现在有中性人了) 
  5.               public string Title{get,set;}//称谓 
  6.               public int    Age{set,get;}//年龄 
  7.          } 

然后我们就可以开始工作,打开vs2010 创建一个silverlight应用程序 family.sln.进入设计界面,照着步骤往下,想不明白也别管,到了最后你就完全明白了。
1.在解决方案管理按MVVM的模式新建Views、Models、viewmodels、commands文件夹,这个不是必须的,但是真正做项目的时候是必须,你的组织你的程序文件啊!否则成百上千的文件,你要找个文件都得找成近视眼;
2.在models文件夹下新建一个类familymember.cs,照抄上面的;

[csharp] view plain copy print ?
  1. public class familymember//家庭成员类 
  2.        { 
  3.             public string Name{getset;}--姓名 
  4.             public string Sex{getset;}--性别(不使用bool,因为现在有中性人了) 
  5.             public string Title{getset;}--称谓 
  6.             public int    Age{setget;}--年龄 
  7.        } 

3.继续在models文件下再新建一个类family.cs,当然你可以不另外创建,直接写在familymember.cs里面
[csharp] view plain copy print ?
  1. using System.Collections.Generic;//List类在此名称空间下 
  2.          public class family//家庭类(就是familymember类的集合) 
  3.          public class family 
  4.             { 
  5.                  private List<familymember> _family; 
  6.                  public List<familymember> initfamily() 
  7.                      { 
  8.                         _family = new List<familymember>() 
  9.                            { 
  10.                                 new familymember{Name="王大爷",Age=120,Sex="男",Title="太爷"}, 
  11.                                 new familymember{Name="王老爷",Age=80,Sex="男",Title="爷爷"}, 
  12.                                 new familymember {Name="王中钱",Age=50,Sex="男",Title="老爸"}, 
  13.                                 new familymember {Name="王夫人",Age=48,Sex="女",Title="老妈"}, 
  14.                                 new familymember {Name ="王大二",Age=25,Sex="男",Title="大儿子"}, 
  15.                                 new familymember {Name="王八蛋",Age=20,Sex="男",Title="小儿子"}, 
  16.                                 new familymember {Name ="王小妹",Age=18,Sex="女",Title="小女儿"
  17.                            }; 
  18.                           return _family ; 
  19.                   } 
  20.                } 

4.设计我们的viewmodel文件,在viemodels文件夹下我们新建一个familyviewmodel.cs类
 

[csharp] view plain copy print ?
  1. public class familymodelview 
  2.             { 
  3.               public List<familymember> myfamily {get; set; } 
  4.               public familymodelview() 
  5.             { 
  6.                   //构造函数中初始化家庭成员列表 
  7.                   myfamily = new family().initfamily(); 
  8.              } 
  9.              } 


5.在views下面建一个文件familyview.xaml,这个是用来显示家庭成员的;
[html] view plain copy print ?
  1. <Gridx:Name="LayoutRoot"Background="White"> 
  2.        <Grid.RowDefinitions> 
  3.            <RowDefinitionHeight="auto"/> 
  4.            <RowDefinition/> 
  5.        </Grid.RowDefinitions> 
  6.        <StackPanelOrientation="Horizontal"> 
  7.        <TextBlockText="输入查询条件"/> 
  8.        <TextBoxName="txtsearch"Width="100"Height="23"/> 
  9.         <ButtonName="btnsearch"Content="查询"/> 
  10.         <ButtonName="btnadd"Content="添加"/> 
  11.         <ButtonName="btndel"Content="删除"/> 
  12.        </StackPanel> 
  13.        <sdk:DataGridGrid.Row="1"Width="300"Name="mygrid"  ItemsSource="{Binding myfamily}"    HorizontalAlignment="Left"IsReadOnly="True"> 
  14.            <sdk:DataGrid.Columns> 
  15.                <sdk:DataGridTextColumnBinding="{Binding Name}"Header="姓名"Width="80"/> 
  16.                <sdk:DataGridTextColumnBinding="{Binding Title}"Header="称谓"Width="80"/> 
  17.                <sdk:DataGridTextColumnBinding="{Binding Sex}"Header="性别"Width="50"/> 
  18.                <sdk:DataGridTextColumnBinding="{Binding Age}"Header="年龄"Width="50"/> 
  19.                <sdk:DataGridTemplateColumnx:Name="c1"Header="删除"> 
  20.                    <sdk:DataGridTemplateColumn.CellTemplate> 
  21.                        <DataTemplate> 
  22.                            <ButtonName="btndelete"Content="Del"Click="btndelete_Click"/> 
  23.                        </DataTemplate> 
  24.                    </sdk:DataGridTemplateColumn.CellTemplate> 
  25.                </sdk:DataGridTemplateColumn> 
  26.            </sdk:DataGrid.Columns> 
  27.        </sdk:DataGrid> 
  28.    </Grid> 

6.开始拼装,在Mainpage.xaml文件中写上

[html] view plain copy print ?
  1. <Gridx:Name="LayoutRoot"Background="White"> 
  2.              <local:familyview/> 
  3.         </Grid> 


同时在cs文件中,将mainpage的构造函数修改一下:
[csharp] view plain copy print ?
  1. public MainPage() 
  2.           { 
  3.             InitializeComponent(); 
  4.             this.LayoutRoot.DataContext =new familymodelview(); 
  5.           } 


7.运行一下,是不是看见了家庭成员列表。比起以前的asp.net开发是不是很繁杂啊,一点都不习惯啊!例子到这里好像还是没有看出太大的端倪,但应该可以看出view文件已经很白了,我们继续往下。

8.现在王小二娶了媳妇董雨进门,那么这个家庭列表就增加了,我们需要添加方法,如果是asp.net,在view.cs文件调用一下解决了,但这样那个xaml文件又复杂了,理性人和感性人又得纠结了。在mvvm中这个要玩的是familymodelview.cs这个文件。添加一个addmember方法

[csharp] view plain copy print ?
  1. public void addmember(familymember p) 
  2.      { 
  3.           MessageBox.Show("恭喜,你的家庭成员增加了"); 
  4.      } 

同时我们把查询和删除的方法也添加上.......
9.方法添加完了,我们需要把这个方法绑定到view里面的添加按钮上,这个时候就需要用到Icommand接口了。在commad下建一个relaycommand.cs

[csharp] view plain copy print ?
  1. public class relaycommand:ICommand 
  2.     { 
  3.       private bool _isenabled; 
  4.       private Action _handler; 
  5.       public relaycommand(Action handler) 
  6.       { 
  7.           handler = _handler; 
  8.       } 
  9.       public bool IsEnabled 
  10.       { 
  11.           get { return _isenabled; } 
  12.           set 
  13.           { 
  14.               _isenabled = value; 
  15.               if (CanExecuteChanged !=null
  16.               { 
  17.                   this.CanExecuteChanged(this, EventArgs.Empty); 
  18.               } 
  19.           } 
  20.       } 
  21.       public bool CanExecute(object parameter) 
  22.       { 
  23.           //throw new NotImplementedException(); 
  24.           return IsEnabled; 
  25.       } 
  26.       public event EventHandler CanExecuteChanged; 
  27.       public void Execute(object parameter) 
  28.       { 
  29.           //throw new NotImplementedException(); 
  30.           _handler(); 
  31.       } 
  32.   } 

10.回到familymodelview.cs里面添加上一些语句,完整程序的如下

[csharp] view plain copy print ?
  1. public List<familymember> myfamily {get; set; } 
  2.         public string searchtext {get; set; }//这个是用于和那个搜索条件绑定用的 
  3.         private ICommand _addfamilymembercommand; 
  4.         private ICommand _deletefamilymembercommand; 
  5.         private ICommand _searchmembercommand; 
  6.         public ICommand addfamilymembercommand 
  7.         { 
  8.             get { return _addfamilymembercommand; } 
  9.         } 
  10.         public ICommand deletefamilymembercommand 
  11.         { 
  12.             get { return _deletefamilymembercommand; } 
  13.         } 
  14.         public ICommand searchmembercommand 
  15.         { 
  16.             get { return _searchmembercommand; } 
  17.         } 
  18.         //构造函数 
  19.         public familymodelview() 
  20.         { 
  21.             myfamily = new family().initfamily(); 
  22.             _searchmembercommand = new relaycommand(searchfamilymember) { IsEnabled =true }; 
  23.             _addfamilymembercommand = new relaycommand(addfamilymember) { IsEnabled = true }; 
  24.             _deletefamilymembercommand = new relaycommand(removefamilymember) { IsEnabled =true }; 
  25.         } 
  26.         //实现功能的方法 
  27.         public void addfamilymember() 
  28.         { 
  29.             MessageBox.Show("恭喜,你的家庭成员增加了"); 
  30.         } 
  31.         public void removefamilymember() 
  32.         { 
  33.             MessageBox.Show("sorry,你的家庭成员减少了"); 
  34.         } 
  35.         public void searchfamilymember() 
  36.         { 
  37.             List<familymember> mylists = null
  38.             if (!string.IsNullOrEmpty(searchtext)) 
  39.             { 
  40.                 mylists = new List<familymember>(); 
  41.                 foreach (familymember pin myfamily) 
  42.                 { 
  43.                     if (p.Name.Contains(searchtext)) 
  44.                         mylists.Add(p); 
  45.                 } 
  46.                 myfamily = mylists; 
  47.             } 
  48.            
  49.         } 
  50.     } 

10.这个时候回到view界面,程序再狠,也不可能知道艺术家在xaml文件中发挥到天上还是地上,所以作为程序员的你还需要在多废点脑细胞,谁让你能呢!如果说view是个美人,那viewmodel是view背后的那个男人,view要发挥作用是离不开viewmodel的,在view的cs文件中写上:

[csharp] view plain copy print ?
  1. public partial class familyview : UserControl 
  2.      { 
  3.           familymodelview family1 = new familymodelview(); 
  4.           public familyview() 
  5.            { 
  6.               InitializeComponent(); 
  7.             } 
  8.       private void btndelete_Click(object sender, RoutedEventArgs e) 
  9.       { 
  10.          family1. 
  11.       } 
  12.       private void btnsearch_Click(object sender, RoutedEventArgs e) 
  13.       { 
  14.           family1.searchtext = this.txtsearch.Text.Trim(); 
  15.           family1.searchmembercommand.Execute(null ); 
  16.       } 
  17.   } 

运行一下看看,点击添加和删除,是不是提示成功了。别以为到这里就真的会了mvvm,仔细想想,是不是有一点感觉:绕老绕去的写了好多代码其实都是在做无用功,特别是那个Icommand接口。如果你这么想,就说明你真的用心学了。
11.真谛:如果mvvm是象上面那样写程序,那还不如不要呢!记得前面我们白话的时候提过,view就像美女一样,基本靠“绑”,所以删除我们的哪些语句,让click事件滚蛋,直接在view的xaml文件中把命令绑上去。代码如下:

[html] view plain copy print ?
  1. <ButtonName="btnsearch"Content="查询"Command="{Binding searchmembercommand}"/> 
  2.            <ButtonName="btnadd"Content="添加"Command="{Binding addfamilymembercommand}"/> 
  3.            <ButtonName="btndel"Content="删除"Command="{Binding deletefamilymembercommand}"/> 


12.再次运行,看看是不是一样的效果。现在你应该明白这种模式的优势了吧,界面设计和程序设计者之间的自由度是不是发挥到了极致。

不过程序到这里其实还没有完.....

你可能感兴趣的:(WPF之MVVM解析)