【学习笔记】Silverlight框架:Jounce(7)——ViewRouter和ViewModelRouter

ViewRouter和ViewModelRouter可以说是Jounce里的核心之一,特别是在MVVM的应用上。

-

ViewRouter实现了3个接口,分别是IFluentViewXapRouter, IPartImportsSatisfiedNotification和IEventSink<ViewNavigationArgs>。IFluentViewXapRouter主要是涉及到模块化管理,下次再说。根据上次事件通信里所讲的,通过IEventSink<ViewNavigationArgs>和IPartImportsSatisfiedNotification的合作,ViewRouter订阅了类型是ViewNavigationArgs的消息,而ViewNavigationArgs里有个属性是ViewType用于指定当前操作的视图。

-

以框架启动为例,启动时ApplicationService会发布一个类型为ViewNavigationArgs的消息,其中的ViewType是当前的Shell,这样ViewRouter就会捕获到这个消息, 首先它会通过模块化管理判断这个视图要不要去别的模块里下载(当然,Shell是肯定不用下载的,要不一开始就会启动失败),不管要不要下载最后都会调用ViewRouter里[Import]的IViewModelRouter的ActivateView方法。

-

IViewModelRouter是ViewModelRouter实现的一个主要接口,另外一个是IFluentViewModelRouter。前面我们演示过通过[Export]路由ViewModelRoute(注意名字区分,ViewModelRoute和ViewModelRouter)来关联View和ViewModel,而IFluentViewModelRouter则是实现两者关联的另一种选择,也还是在模块化管理里再讲(虽然不一定要在模块化中才能用)。

-

IViewModelRouter里定义了一系列操作View和ViewModel的方法。在ViewModelRouter的实现里,ActivateView会去为当前操作的View查找匹配的BaseViewModel,进行互相绑定(BaseViewModel也会持有View的引用)和初始化,并最终调用BaseViewModel.Activate方法。当继承BaseViewModel时,可以重写ActivateView方法(在上一篇的例子中就重写了MainViewModel里的这个方法),实现激活时的相关操作。剩下的就是各种各样获取View和ViewModel的方法了。其中的GetNonSharedViewModel和GetNonSharedView提供了不同版本的重载,可以用于获取ViewModel和View的新实例,在创建和绑定集合的时候比较有用。

-

来点例子看看NonShare的使用,继续借用下我们可爱的马达加斯加的动物们,结构如下:

-

AnimalViewModel定义了很简单的结构:

AnimalViewModel
 1     public class AnimalViewModel : BaseViewModel
2 {
3 public string Name { get; set; }
4 public string Describe { get; set; }
5 }
6
7 [ExportAsViewModel(typeof(PenguinViewModel))]
8 public class PenguinViewModel : AnimalViewModel
9 {
10 protected override void ActivateView(string viewName, IDictionary<string, object> viewParameters)
11 {
12 this.EventAggregator.Publish<string>(
13 string.Format("哈哈,我是{0}的企鹅:{1}", this.Describe, this.Name));
14 }
15 }
16
17 [ExportAsViewModel(typeof(LemurViewModel))]
18 public class LemurViewModel : AnimalViewModel
19 {
20 protected override void ActivateView(string viewName, IDictionary<string, object> viewParameters)
21 {
22 this.EventAggregator.Publish<string>(
23 string.Format("哈哈,我是{0}的狐猴:{1}", this.Describe, this.Name));
24 }
25 }

-

对应于每种动物需要定义不同的视图:

PenguinView
 1 <UserControl x:Class="JounceNoShareView.PenguinView"
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 d:DesignHeight="300" d:DesignWidth="400">
8
9 <Grid x:Name="LayoutRoot" Background="White">
10 <Grid Background="Black">
11 <Grid.RowDefinitions>
12 <RowDefinition Height="0.2*"/>
13 <RowDefinition Height="0.6*"/>
14 <RowDefinition Height="0.2*"/>
15 </Grid.RowDefinitions>
16 <Grid.ColumnDefinitions>
17 <ColumnDefinition Width="0.2*"/>
18 <ColumnDefinition Width="0.6*"/>
19 <ColumnDefinition Width="0.2*"/>
20 </Grid.ColumnDefinitions>
21 <Rectangle Grid.Column="1" Fill="White" Grid.Row="1"/>
22 <TextBlock Grid.Column="1" Grid.Row="1"
23 HorizontalAlignment="Center" VerticalAlignment="Center"
24 Text="{Binding Name}"/>
25 </Grid>
26 </Grid>
27 </UserControl>
LemurView
 1 <UserControl x:Class="JounceNoShareView.LemurView"
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 d:DesignHeight="300" d:DesignWidth="400">
8
9 <Grid x:Name="LayoutRoot" Background="White">
10 <Grid.ColumnDefinitions>
11 <ColumnDefinition Width="0.5*"/>
12 <ColumnDefinition Width="0.5*"/>
13 </Grid.ColumnDefinitions>
14 <TextBlock Text="{Binding Name}" Margin="2"/>
15 <Rectangle Grid.Column="1">
16 <Rectangle.Fill>
17 <LinearGradientBrush EndPoint="0,0" StartPoint="10,0" SpreadMethod="Repeat" MappingMode="Absolute">
18 <GradientStop Color="Black" Offset="0"/>
19 <GradientStop Color="Black" Offset="0.5"/>
20 <GradientStop Color="White" Offset="0.5"/>
21 <GradientStop Color="White" Offset="1"/>
22 </LinearGradientBrush>
23 </Rectangle.Fill>
24 </Rectangle>
25 </Grid>
26 </UserControl>

-

MainViewModel提供简单的动物集合,重写了基类的方法InitializeVm:

MainViewModel
 1     [ExportAsViewModel("MainViewModel")]
2 public class MainViewModel : BaseViewModel
3 {
4 public IEnumerable<AnimalViewModel> AnimalViewModels { get; private set; }
5
6 protected override void InitializeVm()
7 {
8 var animals = new List<AnimalViewModel>();
9
10 animals.Add(this.GetAnimal<PenguinViewModel>("老大", "勇敢机智"));
11 animals.Add(this.GetAnimal<PenguinViewModel>("卡哇伊", "文武双全"));
12 animals.Add(this.GetAnimal<PenguinViewModel>("凉快", "拥有无敌胃"));
13 animals.Add(this.GetAnimal<PenguinViewModel>("菜鸟", "温柔善良"));
14
15 animals.Add(this.GetAnimal<LemurViewModel>("朱利安国王", "伟大"));
16 animals.Add(this.GetAnimal<LemurViewModel>("大毛", "忠诚"));
17 animals.Add(this.GetAnimal<LemurViewModel>("小毛", "爱抱国王大腿"));
18
19 this.AnimalViewModels = animals;
20 this.RaisePropertyChanged(() => AnimalViewModels);
21 }
22
23 private T GetAnimal<T>(string name, string describe) where T : AnimalViewModel
24 {
25 var animal = this.Router.GetNonSharedViewModel<T>();
26 animal.Name = name;
27 animal.Describe = describe;
28 return animal;
29 }
30 }

-

可以看到在AnimalViewModel被激活的时候会Publish一个消息出来,这个消息会在MainPage里捕获,并在UI上呈现出来:

MainPage.xaml.cs
 1     [ExportAsView("MainPage", IsShell = true)]
2 public partial class MainPage : UserControl, IPartImportsSatisfiedNotification, IEventSink<string>
3 {
4 [Import]
5 public IEventAggregator EventAggregator { get; set; }
6
7 public MainPage()
8 {
9 InitializeComponent();
10 }
11
12 public void HandleEvent(string publishedEvent)
13 {
14 this.OutTextBox.Text += publishedEvent + "\r\n";
15 }
16
17 public void OnImportsSatisfied()
18 {
19 this.EventAggregator.Subscribe(this);
20 }
21 }

看一下UI上的设置:

MainPage.xaml
 1 <UserControl x:Class="JounceNoShareView.MainPage"
2 xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
6 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
7 xmlns:ViewModel="clr-namespace:Jounce.Framework.ViewModel;assembly=Jounce"
8 mc:Ignorable="d"
9 d:DesignHeight="300" d:DesignWidth="400">
10
11 <UserControl.Resources>
12 <ViewModel:JounceViewConverter x:Key="ViewConverter"/>
13 </UserControl.Resources>
14
15 <Grid x:Name="LayoutRoot" Background="White">
16 <Grid.RowDefinitions>
17 <RowDefinition Height="Auto"/>
18 <RowDefinition/>
19 </Grid.RowDefinitions>
20 <ItemsControl ItemsSource="{Binding AnimalViewModels}" Margin="2">
21 <ItemsControl.ItemTemplate>
22 <DataTemplate>
23 <Border Height="100" Width="160" Margin="1"
24 BorderBrush="LightBlue" BorderThickness="1"
25 Child="{Binding Converter={StaticResource ViewConverter}}"/>
26 </DataTemplate>
27 </ItemsControl.ItemTemplate>
28 <ItemsControl.ItemsPanel>
29 <ItemsPanelTemplate>
30 <toolkit:WrapPanel Orientation="Horizontal"/>
31 </ItemsPanelTemplate>
32 </ItemsControl.ItemsPanel>
33 </ItemsControl>
34 <TextBox Margin="2" Grid.Row="1" x:Name="OutTextBox"/>
35 </Grid>
36 </UserControl>

-

最后就是Bindings里的一些关联信息了:

Bindings
 1     public class Bindings
2 {
3 [Export]
4 public ViewModelRoute MainBinding
5 {
6 get { return ViewModelRoute.Create("MainViewModel", "MainPage"); }
7 }
8
9 [Export]
10 public ViewModelRoute PenguinBinding
11 {
12 get { return ViewModelRoute.Create<PenguinViewModel, PenguinView>(); }
13 }
14
15 [Export]
16 public ViewModelRoute LemurBinding
17 {
18 get { return ViewModelRoute.Create<LemurViewModel, LemurView>(); }
19 }
20 }

-

看一下效果如何:

-

可以看到创建NonSharedViewModel的方法我们是自己在代码里实现的,当绑定到集合时,用到了JounceViewConverter,这是Jounce里自带的,进一步封装了GetNonSharedView方法,这样就可以为每个ViewModel创建独立的View,并为不同类型的ViewModel创建不同的View。

要使用JounceViewConverter的话子项必须实现IViewModel接口并添加[ExportAsViewModel]和ViewModelRoute信息,而如果要进一步在绑定View后实现IViewModel里的初始化和激活功能的话则必须继承自BaseViewModel。

实际应用中我们常常创建Model集合而不是ViewModel集合进行绑定,这就需要进一步封装Model或者根据Jounce里的思路自己实现一些扩展功能了。

posted @ 2011-08-09 21:31  超时空饭盒  阅读(1002)  评论(3编辑  收藏  举报