我们前面一节白话白眼,都只是从概念上了解了mvvm,了解和做还是差距很大,所以我们同样需要亲自动手实验来真的弄懂mvvm。
例子就取一个生活中的,用mvvm模式完成家庭的操作,比如显示查询家庭成员,增加家庭成员(娶妻生子等),减少家庭成员(嫁女老去等).
确定好这个例子我们就需要先准备一下数据,我们首先想到可能是用数据库,不过silverlight是浏览器客户端的东西,是不能和你以前使用asp.net一样主动直接连接数据库的,如果你真的要开始就连接数据库,你还得准备另外学习一些知识。
我们先构思一下自己的类的样子:
[csharp] view plain copy print ?
- class familymember
- {
- public string Name{get,set;}
- public string Sex{get,set;}
- public string Title{get,set;}
- public int Age{set,get;}
- }
class familymember
{
public string Name{get,set;}//姓名
public string Sex{get,set;}//性别(不使用bool,因为现在有中性人了)
public string Title{get,set;}//称谓
public int Age{set,get;}//年龄
}
然后我们就可以开始工作,打开vs2010 创建一个silverlight应用程序 family.sln.进入设计界面,照着步骤往下,想不明白也别管,到了最后你就完全明白了。
1.在解决方案管理按MVVM的模式新建Views、Models、viewmodels、commands文件夹,这个不是必须的,但是真正做项目的时候是必须,你的组织你的程序文件啊!否则成百上千的文件,你要找个文件都得找成近视眼;
2.在models文件夹下新建一个类familymember.cs,照抄上面的;
[csharp] view plain copy print ?
- public class familymember
- {
- public string Name{get;set;}--姓名
- public string Sex{get;set;}--性别(不使用bool,因为现在有中性人了)
- public string Title{get;set;}--称谓
- public int Age{set;get;}--年龄
- }
public class familymember//家庭成员类
{
public string Name{get;set;}--姓名
public string Sex{get;set;}--性别(不使用bool,因为现在有中性人了)
public string Title{get;set;}--称谓
public int Age{set;get;}--年龄
}
3.继续在models文件下再新建一个类family.cs,当然你可以不另外创建,直接写在familymember.cs里面
[csharp] view plain copy print ?
- using System.Collections.Generic;
- public class family
- public class family
- {
- private List<familymember> _family;
- public List<familymember> initfamily()
- {
- _family = new List<familymember>()
- {
- new familymember{Name="王大爷",Age=120,Sex="男",Title="太爷"},
- new familymember{Name="王老爷",Age=80,Sex="男",Title="爷爷"},
- new familymember {Name="王中钱",Age=50,Sex="男",Title="老爸"},
- new familymember {Name="王夫人",Age=48,Sex="女",Title="老妈"},
- new familymember {Name ="王大二",Age=25,Sex="男",Title="大儿子"},
- new familymember {Name="王八蛋",Age=20,Sex="男",Title="小儿子"},
- new familymember {Name ="王小妹",Age=18,Sex="女",Title="小女儿"}
- };
- return _family ;
- }
- }
using System.Collections.Generic; //List类在此名称空间下
public class family//家庭类(就是familymember类的集合)
public class family
{
private List<familymember> _family;
public List<familymember> initfamily()
{
_family = new List<familymember>()
{
new familymember{Name="王大爷",Age=120,Sex="男",Title="太爷"},
new familymember{Name="王老爷",Age=80,Sex="男",Title="爷爷"},
new familymember {Name="王中钱",Age=50,Sex="男",Title="老爸"},
new familymember {Name="王夫人",Age=48,Sex="女",Title="老妈"},
new familymember {Name ="王大二",Age=25,Sex="男",Title="大儿子"},
new familymember {Name="王八蛋",Age=20,Sex="男",Title="小儿子"},
new familymember {Name ="王小妹",Age=18,Sex="女",Title="小女儿"}
};
return _family ;
}
}
4.设计我们的viewmodel文件,在viemodels文件夹下我们新建一个familyviewmodel.cs类
[csharp] view plain copy print ?
- public class familymodelview
- {
- public List<familymember> myfamily {get; set; }
- public familymodelview()
- {
-
- myfamily = new family().initfamily();
- }
- }
public class familymodelview
{
public List<familymember> myfamily { get; set; }
public familymodelview()
{
//构造函数中初始化家庭成员列表
myfamily = new family().initfamily();
}
}
5.在views下面建一个文件familyview.xaml,这个是用来显示家庭成员的;
[html] view plain copy print ?
- <Gridx:Name="LayoutRoot"Background="White">
- <Grid.RowDefinitions>
- <RowDefinitionHeight="auto"/>
- <RowDefinition/>
- </Grid.RowDefinitions>
- <StackPanelOrientation="Horizontal">
- <TextBlockText="输入查询条件"/>
- <TextBoxName="txtsearch"Width="100"Height="23"/>
- <ButtonName="btnsearch"Content="查询"/>
- <ButtonName="btnadd"Content="添加"/>
- <ButtonName="btndel"Content="删除"/>
- </StackPanel>
- <sdk:DataGridGrid.Row="1"Width="300"Name="mygrid" ItemsSource="{Binding myfamily}" HorizontalAlignment="Left"IsReadOnly="True">
- <sdk:DataGrid.Columns>
- <sdk:DataGridTextColumnBinding="{Binding Name}"Header="姓名"Width="80"/>
- <sdk:DataGridTextColumnBinding="{Binding Title}"Header="称谓"Width="80"/>
- <sdk:DataGridTextColumnBinding="{Binding Sex}"Header="性别"Width="50"/>
- <sdk:DataGridTextColumnBinding="{Binding Age}"Header="年龄"Width="50"/>
- <sdk:DataGridTemplateColumnx:Name="c1"Header="删除">
- <sdk:DataGridTemplateColumn.CellTemplate>
- <DataTemplate>
- <ButtonName="btndelete"Content="Del"Click="btndelete_Click"/>
- </DataTemplate>
- </sdk:DataGridTemplateColumn.CellTemplate>
- </sdk:DataGridTemplateColumn>
- </sdk:DataGrid.Columns>
- </sdk:DataGrid>
- </Grid>
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions >
<RowDefinition Height="auto"/>
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" >
<TextBlock Text="输入查询条件"/>
<TextBox Name="txtsearch" Width="100" Height="23"/>
<Button Name="btnsearch" Content="查询"/>
<Button Name="btnadd" Content="添加"/>
<Button Name="btndel" Content="删除"/>
</StackPanel>
<sdk:DataGrid Grid.Row="1" Width="300" Name="mygrid" ItemsSource="{Binding myfamily}" HorizontalAlignment="Left" IsReadOnly="True">
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn Binding="{Binding Name}" Header="姓名" Width="80"/>
<sdk:DataGridTextColumn Binding="{Binding Title}" Header="称谓" Width="80"/>
<sdk:DataGridTextColumn Binding="{Binding Sex}" Header="性别" Width="50"/>
<sdk:DataGridTextColumn Binding="{Binding Age}" Header="年龄" Width="50"/>
<sdk:DataGridTemplateColumn x:Name="c1" Header="删除" >
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Name="btndelete" Content="Del" Click="btndelete_Click"/>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</Grid>
6.开始拼装,在Mainpage.xaml文件中写上
[html] view plain copy print ?
- <Gridx:Name="LayoutRoot"Background="White">
- <local:familyview/>
- </Grid>
<Grid x:Name="LayoutRoot" Background="White" >
<local:familyview/>
</Grid>
同时在cs文件中,将mainpage的构造函数修改一下:
[csharp] view plain copy print ?
- public MainPage()
- {
- InitializeComponent();
- this.LayoutRoot.DataContext =new familymodelview();
- }
public MainPage()
{
InitializeComponent();
this.LayoutRoot.DataContext = new familymodelview();
}
7.运行一下,是不是看见了家庭成员列表。比起以前的asp.net开发是不是很繁杂啊,一点都不习惯啊!例子到这里好像还是没有看出太大的端倪,但应该可以看出view文件已经很白了,我们继续往下。
8.现在王小二娶了媳妇董雨进门,那么这个家庭列表就增加了,我们需要添加方法,如果是asp.net,在view.cs文件调用一下解决了,但这样那个xaml文件又复杂了,理性人和感性人又得纠结了。在mvvm中这个要玩的是familymodelview.cs这个文件。添加一个addmember方法
[csharp] view plain copy print ?
- public void addmember(familymember p)
- {
- MessageBox.Show("恭喜,你的家庭成员增加了");
- }
public void addmember(familymember p)
{
MessageBox.Show("恭喜,你的家庭成员增加了");
}
同时我们把查询和删除的方法也添加上.......
9.方法添加完了,我们需要把这个方法绑定到view里面的添加按钮上,这个时候就需要用到Icommand接口了。在commad下建一个relaycommand.cs
[csharp] view plain copy print ?
- public class relaycommand:ICommand
- {
- private bool _isenabled;
- private Action _handler;
- public relaycommand(Action handler)
- {
- handler = _handler;
- }
- public bool IsEnabled
- {
- get { return _isenabled; }
- set
- {
- _isenabled = value;
- if (CanExecuteChanged !=null)
- {
- this.CanExecuteChanged(this, EventArgs.Empty);
- }
- }
- }
- public bool CanExecute(object parameter)
- {
-
- return IsEnabled;
- }
- public event EventHandler CanExecuteChanged;
- public void Execute(object parameter)
- {
-
- _handler();
- }
- }
public class relaycommand:ICommand
{
private bool _isenabled;
private Action _handler;
public relaycommand(Action handler)
{
handler = _handler;
}
public bool IsEnabled
{
get { return _isenabled; }
set
{
_isenabled = value;
if (CanExecuteChanged != null)
{
this.CanExecuteChanged(this, EventArgs.Empty);
}
}
}
public bool CanExecute(object parameter)
{
//throw new NotImplementedException();
return IsEnabled;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
//throw new NotImplementedException();
_handler();
}
}
10.回到familymodelview.cs里面添加上一些语句,完整程序的如下
[csharp] view plain copy print ?
- public List<familymember> myfamily {get; set; }
- public string searchtext {get; set; }
- private ICommand _addfamilymembercommand;
- private ICommand _deletefamilymembercommand;
- private ICommand _searchmembercommand;
- public ICommand addfamilymembercommand
- {
- get { return _addfamilymembercommand; }
- }
- public ICommand deletefamilymembercommand
- {
- get { return _deletefamilymembercommand; }
- }
- public ICommand searchmembercommand
- {
- get { return _searchmembercommand; }
- }
-
- public familymodelview()
- {
- myfamily = new family().initfamily();
- _searchmembercommand = new relaycommand(searchfamilymember) { IsEnabled =true };
- _addfamilymembercommand = new relaycommand(addfamilymember) { IsEnabled = true };
- _deletefamilymembercommand = new relaycommand(removefamilymember) { IsEnabled =true };
- }
-
- public void addfamilymember()
- {
- MessageBox.Show("恭喜,你的家庭成员增加了");
- }
- public void removefamilymember()
- {
- MessageBox.Show("sorry,你的家庭成员减少了");
- }
- public void searchfamilymember()
- {
- List<familymember> mylists = null;
- if (!string.IsNullOrEmpty(searchtext))
- {
- mylists = new List<familymember>();
- foreach (familymember pin myfamily)
- {
- if (p.Name.Contains(searchtext))
- mylists.Add(p);
- }
- myfamily = mylists;
- }
-
- }
- }
public List<familymember> myfamily { get; set; }
public string searchtext { get; set; }//这个是用于和那个搜索条件绑定用的
private ICommand _addfamilymembercommand;
private ICommand _deletefamilymembercommand;
private ICommand _searchmembercommand;
public ICommand addfamilymembercommand
{
get { return _addfamilymembercommand; }
}
public ICommand deletefamilymembercommand
{
get { return _deletefamilymembercommand; }
}
public ICommand searchmembercommand
{
get { return _searchmembercommand; }
}
//构造函数
public familymodelview()
{
myfamily = new family().initfamily();
_searchmembercommand = new relaycommand(searchfamilymember) { IsEnabled = true };
_addfamilymembercommand = new relaycommand(addfamilymember) { IsEnabled = true };
_deletefamilymembercommand = new relaycommand(removefamilymember) { IsEnabled = true };
}
//实现功能的方法
public void addfamilymember()
{
MessageBox.Show("恭喜,你的家庭成员增加了");
}
public void removefamilymember()
{
MessageBox.Show("sorry,你的家庭成员减少了");
}
public void searchfamilymember()
{
List<familymember> mylists = null;
if (!string.IsNullOrEmpty(searchtext))
{
mylists = new List<familymember>();
foreach (familymember p in myfamily)
{
if (p.Name.Contains(searchtext))
mylists.Add(p);
}
myfamily = mylists;
}
}
}
10.这个时候回到view界面,程序再狠,也不可能知道艺术家在xaml文件中发挥到天上还是地上,所以作为程序员的你还需要在多废点脑细胞,谁让你能呢!如果说view是个美人,那viewmodel是view背后的那个男人,view要发挥作用是离不开viewmodel的,在view的cs文件中写上:
[csharp] view plain copy print ?
- public partial class familyview : UserControl
- {
- familymodelview family1 = new familymodelview();
- public familyview()
- {
- InitializeComponent();
- }
- private void btndelete_Click(object sender, RoutedEventArgs e)
- {
- family1.
- }
- private void btnsearch_Click(object sender, RoutedEventArgs e)
- {
- family1.searchtext = this.txtsearch.Text.Trim();
- family1.searchmembercommand.Execute(null );
- }
- }
public partial class familyview : UserControl
{
familymodelview family1 = new familymodelview();
public familyview()
{
InitializeComponent();
}
private void btndelete_Click(object sender, RoutedEventArgs e)
{
family1.
}
private void btnsearch_Click(object sender, RoutedEventArgs e)
{
family1.searchtext = this.txtsearch.Text.Trim();
family1.searchmembercommand.Execute(null );
}
}
运行一下看看,点击添加和删除,是不是提示成功了。别以为到这里就真的会了mvvm,仔细想想,是不是有一点感觉:绕老绕去的写了好多代码其实都是在做无用功,特别是那个Icommand接口。如果你这么想,就说明你真的用心学了。
11.真谛:如果mvvm是象上面那样写程序,那还不如不要呢!记得前面我们白话的时候提过,view就像美女一样,基本靠“绑”,所以删除我们的哪些语句,让click事件滚蛋,直接在view的xaml文件中把命令绑上去。代码如下:
[html] view plain copy print ?
- <ButtonName="btnsearch"Content="查询"Command="{Binding searchmembercommand}"/>
- <ButtonName="btnadd"Content="添加"Command="{Binding addfamilymembercommand}"/>
- <ButtonName="btndel"Content="删除"Command="{Binding deletefamilymembercommand}"/>
<Button Name="btnsearch" Content="查询" Command="{Binding searchmembercommand}"/>
<Button Name="btnadd" Content="添加" Command="{Binding addfamilymembercommand}" />
<Button Name="btndel" Content="删除" Command="{Binding deletefamilymembercommand}" />
12.再次运行,看看是不是一样的效果。现在你应该明白这种模式的优势了吧,界面设计和程序设计者之间的自由度是不是发挥到了极致。
不过程序到这里其实还没有完.....