做WPF/Silverlight/Windows Phone 7 这种Markup+Code类型的项目,程序员和Blend的Designer配合起来有时候真是一个“抓狂”,最近研究了MVVM模式后深切体会到这个模式的优越性,我研究不不是很深,希望走过路过的高手多多指教!
先贴个图:
按照MVVM模式的思想编写的程序应该在思想上抛弃Xaml文件的code behind(即xaml.cs)文件,这样才能让coder和designer各尽其能。coder需要做的就是在designer设计好的xaml文件里对UI控件的值进行Binding,这里应该会用到Command和Behavior。
在我要做到例子里,我需要对UI的Event监听,实现方法将event绑定到Command(这里需要用到一个MVVM Light Toolkit框架,
GalaSoft.MvvmLight, 此下载的文件中包括WPF/Silverlight/WP7的dll版本),而不是用原来的注册event事件(当然这也是MVVM的思想)。关于MVVM Light Toolkit,可以看
这篇文章。
接下来我开始展示一个小Demo:
1. 首先看一下我的项目目录及引用的程序集:
2. view里的ContractsItem, 这个view是展示每个联系人的控件,这个控件很简单,只是简单的绑定了姓名和电话
View Code
1
<
UserControl x:Class
=
"
TwitterPlatform.Views.ContactsItem
"
2
xmlns
=
"
http://schemas.microsoft.com/winfx/2006/xaml/presentation
"
3
xmlns:x
=
"
http://schemas.microsoft.com/winfx/2006/xaml
"
4
xmlns:d
=
"
http://schemas.microsoft.com/expression/blend/2008
"
5
xmlns:i
=
"
clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity
"
6
xmlns:lightToolkit
=
"
clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP7
"
7
xmlns:mc
=
"
http://schemas.openxmlformats.org/markup-compatibility/2006
"
8
xmlns:vm
=
"
clr-namespace:TwitterPlatform.ViewModel
"
9
mc:Ignorable
=
"
d
"
10
FontFamily
=
"
{StaticResource PhoneFontFamilyNormal}
"
11
FontSize
=
"
{StaticResource PhoneFontSizeNormal}
"
12
Foreground
=
"
{StaticResource PhoneForegroundBrush}
"
13
Width
=
"
250
"
Height
=
"
90
"
>
14
<
UserControl.Resources
>
15
<
vm:ContactsItemViewModel x:Key
=
"
ContactsItemViewModel
"
></
vm:ContactsItemViewModel
>
16
</
UserControl.Resources
>
17
18
<
StackPanel Orientation
=
"
Horizontal
"
x:Name
=
"
LayoutRoot
"
Background
=
"
Transparent
"
>
19
<
i:Interaction.Triggers
>
20
<
i:EventTrigger EventName
=
"
MouseLeftButtonDown
"
>
21
<
lightToolkit:EventToCommand
22
Command
=
"
{Binding ShowMessageBoxCommand, Source={StaticResource ContactsItemViewModel}}
"
23
CommandParameter
=
"
{Binding Path=Text, ElementName=NameField}
"
24
></
lightToolkit:EventToCommand
>
25
</
i:EventTrigger
>
26
</
i:Interaction.Triggers
>
27
<
Image Width
=
"
90
"
Height
=
"
90
"
Source
=
"
/Images/Person.png
"
></
Image
>
28
<
StackPanel Margin
=
"
12,0,12,0
"
Orientation
=
"
Vertical
"
>
29
<
TextBlock x:Name
=
"
NameField
"
Text
=
"
{Binding Name, Mode=OneWay}
"
Margin
=
"
0,10,0,20
"
></
TextBlock
>
30
<
TextBlock Text
=
"
{Binding Tel, Mode=OneWay}
"
></
TextBlock
>
31
</
StackPanel
>
32
</
StackPanel
>
33
</
UserControl
>
3. view里的ContractsList.xaml,这个view负责显示所有的联系人列表,列表的数据加载方式有两种,一种是用command绑定viewmodel的command,另一种是让viewmodel实现IEnumerable接口,这两种方法我都例子里都会有所显示
View Code
1
<
UserControl x:Class
=
"
TwitterPlatform.Views.ContactsList
"
2
xmlns
=
"
http://schemas.microsoft.com/winfx/2006/xaml/presentation
"
3
xmlns:x
=
"
http://schemas.microsoft.com/winfx/2006/xaml
"
4
xmlns:d
=
"
http://schemas.microsoft.com/expression/blend/2008
"
5
xmlns:mc
=
"
http://schemas.openxmlformats.org/markup-compatibility/2006
"
6
mc:Ignorable
=
"
d
"
7
FontFamily
=
"
{StaticResource PhoneFontFamilyNormal}
"
8
FontSize
=
"
{StaticResource PhoneFontSizeNormal}
"
9
Foreground
=
"
{StaticResource PhoneForegroundBrush}
"
10
xmlns:views
=
"
clr-namespace:TwitterPlatform.Views
"
11
xmlns:vm
=
"
clr-namespace:TwitterPlatform.ViewModel
"
12
xmlns:i
=
"
clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity
"
13
xmlns:lightToolkit
=
"
clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP7
"
14
xmlns:command
=
"
clr-namespace:TwitterPlatform.Commands
"
15
xmlns:toolkit
=
"
clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit
"
16
MaxWidth
=
"
800
"
>
17
18
<
Grid x:Name
=
"
LayoutRoot
"
Background
=
"
Transparent
"
>
19
<
Grid.Resources
>
20
<
DataTemplate x:Key
=
"
ItemTemplate
"
>
21
<!--
定义显示每一项数据的数据模板
-->
22
<
views:ContactsItem
>
23
</
views:ContactsItem
>
24
</
DataTemplate
>
25
<!--
定义Xaml对应的ViewModel
-->
26
<
vm:ContactsListViewModel x:Key
=
"
ContractsListViewModel
"
></
vm:ContactsListViewModel
>
27
</
Grid.Resources
>
28
<!--
在这里为了简单起见,我直接把ListBox的DataContext设置为ViewModel,
29
ViewModel实现了IEnumerable),这样list的ItemsSource直接binding就可以
-->
30
<
ListBox DataContext
=
"
{StaticResource ContractsListViewModel}
"
31
ItemsSource
=
"
{Binding}
"
32
ItemTemplate
=
"
{StaticResource ItemTemplate}
"
33
ScrollViewer.HorizontalScrollBarVisibility
=
"
Disabled
"
34
ScrollViewer.VerticalScrollBarVisibility
=
"
Auto
"
>
35
<
ListBox.ItemsPanel
>
36
<
ItemsPanelTemplate
>
37
<
toolkit:WrapPanel
></
toolkit:WrapPanel
>
38
</
ItemsPanelTemplate
>
39
</
ListBox.ItemsPanel
>
40
<!--
对LstBox的loaded事件附件绑定命令,同样,List的数据加载也可以在这个命令excute里进行,然后将ItemsSource绑定到一个集合
-->
41
<
i:Interaction.Triggers
>
42
<
i:EventTrigger EventName
=
"
Loaded
"
>
43
<
lightToolkit:EventToCommand Command
=
"
{Binding LoadedCommand, Mode=OneWay}
"
></
lightToolkit:EventToCommand
>
44
</
i:EventTrigger
>
45
</
i:Interaction.Triggers
>
46
</
ListBox
>
47
</
Grid
>
48
</
UserControl
>
4. ViewModel: ContactsListViewModel.cs 类中定义了Command及IEnumerable的方法
View Code
1
using
System;
2
using
System.Net;
3
using
System.Windows;
4
using
System.Windows.Controls;
5
using
System.Windows.Documents;
6
using
System.Windows.Ink;
7
using
System.Windows.Input;
8
using
System.Windows.Media;
9
using
System.Windows.Media.Animation;
10
using
System.Windows.Shapes;
11
using
System.Collections.Generic;
12
using
TwitterPlatform.Model;
13
using
System.Collections.ObjectModel;
14
using
System.ComponentModel;
15
using
TwitterPlatform.Commands;
16
17
namespace
TwitterPlatform.ViewModel
18
{
19
public
class
ContactsListViewModel : IEnumerable
<
Person
>
20
{
21
22
public
ContactsListViewModel()
23
{
24
this
.LoadedCommand
=
new
ShowMessageCommand();
25
}
26
27
public
ShowMessageCommand LoadedCommand {
get
;
private
set
; }
28
29
//
GetEnumerator() 加载数据
30
public
IEnumerator
<
Person
>
GetEnumerator()
31
{
32
var l
=
new
List
<
Person
>
(){
33
new
Person() { Name
=
"
Michael
"
, Tel
=
"
1234567890
"
},
34
new
Person() { Name
=
"
dali
"
, Tel
=
"
1234567890
"
},
35
new
Person() { Name
=
"
houjun
"
, Tel
=
"
1234567890
"
},
36
new
Person() { Name
=
"
tony
"
, Tel
=
"
1234567890
"
},
37
new
Person() { Name
=
"
jing
"
, Tel
=
"
1234567890
"
},
38
new
Person() { Name
=
"
Joel
"
, Tel
=
"
98564875
"
}
39
};
40
l.Sort();
41
return
l.GetEnumerator();
42
}
43
44
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
45
{
46
return
this
.GetEnumerator();
47
}
48
}
49
}
5. Person类里只定义了Name和Tel两个属性~~
6. 最后是负责显示list的MainPage 了,在这个page里我用了个Paronama,小戏一下呵呵
View Code
1
<!--
2
主要代码
3
xmlns:controls
=
"
clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls
"
4
-->
5
<
Grid x:Name
=
"
ContentPanel
"
Grid.Row
=
"
1
"
Margin
=
"
12,0,12,0
"
>
6
<
controls:Panorama Title
=
"
App List
"
>
7
<
controls:Panorama.Background
>
8
<
ImageBrush ImageSource
=
"
/Images/AppBg.jpg
"
></
ImageBrush
>
9
</
controls:Panorama.Background
>
10
<
controls:PanoramaItem Header
=
"
1. Contacts
"
Orientation
=
"
Horizontal
"
>
11
<
views:ContactsList
></
views:ContactsList
>
12
</
controls:PanoramaItem
>
13
<
controls:PanoramaItem Header
=
"
2. FaceBook
"
>
14
15
</
controls:PanoramaItem
>
16
<
controls:PanoramaItem Header
=
"
3. Others
"
>
17
18
</
controls:PanoramaItem
>
19
</
controls:Panorama
>
20
21
</
Grid
>
22
</
Grid
>
23
以上就是这个小小的Demo,简单的实现了MVVM模式,在这个Demo里主要实现了Event To Command,也是MVVM模式经常用到的东西。
如果有时间我会再做一个更加详细的大一点点demo,呵呵
欢迎讨论~~