像MFC程序一样,在winPhone7程序中,有一个App类。它继承于Application. 程序中的所有类都可以同过静态的Application.Current属性方便的访问这个类的实例。这就意味着你可以使用App类存储你想在程序页面间共享的任何数据。
在SilverlightShareData项目中,我在App类中定义了一个公共属性
Silverlight Project: SilverlightShareData File: App.xaml.cs (excerpt) public partial class App : Application { // public property for sharing data among pages public Color? SharedColor { set; get; } … } |
我定义一个可为Null类型的Color类型属性。这是出于考虑SolidColorBrush在ContentPanel的Background属性中还没有被设置的情况下。在那些情况下,Background 属性是null,而且不应该有Color存储在这个属性中。如果属性只是一个Color类型,那么这个Color属性的值将会被默认存储;这个Color值将是一个透明的黑色,那就错了。如果用户选择亮一点的颜色方案,即便是不透明的黑色,那也是错误的。
多数情况下,程序保持不变,除非当你触摸MainPage中的TextBlock,在导航到SecondPage之前,事件处理函数首先尝试在新的App类属性中保存一个颜色值:
Silverlight Project: SilverlightShareData File: MainPage.xaml.cs (excerpt) void OnTextBlockManipulationStarted(object sender, ManipulationStartedEventArgs args) { if (ContentPanel.Background is SolidColorBrush) (Application.Current as App).SharedColor = (ContentPanel.Background as SolidColorBrush).Color; this.NavigationService.Navigate(new Uri("/SecondPage.xaml", UriKind.Relative)); args.Complete(); args.Handled = true; } |
重载SecondPage中的OnNavigatedTo 来存取这个属性:
Silverlight Project: SilverlightShareData File: SecondPage.xaml.cs (excerpt) protected override void OnNavigatedTo(NavigationEventArgs args) { Color? sharedColor = (Application.Current as App).SharedColor; if (sharedColor != null) ContentPanel.Background = new SolidColorBrush(sharedColor.Value); base.OnNavigatedTo(args); } |
同样,当在SecondPage触发TextBlock时,事件处理函数保存当前背景的颜色到App类中,接着调用GoBack:
Silverlight Project: SilverlightShareData File: SecondPage.xaml.cs (excerpt) void OnTextBlockManipulationStarted(object sender, ManipulationStartedEventArgs args) { if (ContentPanel.Background is SolidColorBrush) (Application.Current as App).SharedColor = (ContentPanel.Background as SolidColorBrush).Color; this.NavigationService.GoBack(); args.Complete(); args.Handled = true; } |
MainPage类也可以重载OnNavigatedTo方法来获取存储的color值,并设置到背景属性:
protected override void OnNavigatedTo(NavigationEventArgs args) { Color? sharedColor = (Application.Current as App).SharedColor; if (sharedColor != null) ContentPanel.Background = new SolidColorBrush(sharedColor.Value); base.OnNavigatedTo(args); } |
现在,我们可以在页面之间切换,颜色信息可以共享了。
使用App类作为仓库在页面之间共享数据是非常的方便。但是我们需要考虑更加结构化的解决方案,仅使用互相需要切换的页面资源,而不是使用一些第三方类,像App.
除了前面提到的OnNavigatedTo 虚拟方法,Page也定义了一个OnNavigatedFrom方法。初看起来这个方法没有什么用。终究,一个page知道自己要导航的其他page是因为它刚刚调用了Navigate或者GoBack.
在OnNavigatedFrom和OnNavigatedTo方法中,他们都有一个NavigationEventArgs事件参数,它定义了两个属性:Uri类型的Uri, 和object类型的Content. 他们表示将要被导向到的page.
我们以MainPage导向到SecondPage为例,简单描述一些事件的处理顺序:
1) MainPage调用Navigate,参数为“/SecondPage.xaml”.
2) MainPage中的OnNavigatedFrom方法被系统调用,传入的Uri属性包含“/SecondPage.xaml”信息,Content属性是SecondPage的新创建的实例对象。
3) SecondPage中的OnNavigatedTo方法被调用,参数与OnNavigatedFrom一样。
类似的,在SecondPage中,如果调用GoBack, 它的OnNavigatedFrom方法就会被调用,参数包括Uri指向“/MainPage.xaml”,Content属性就是MainPage的实例对象。接着,MainPage中的OnNavigatedTo方法被调用,并具有同样的参数信息。
下面然我们看看这个SilverlightInsertData的示例代码。这个项目包括连个page,分别叫MainPage和SecondPage, 他们的XAML文件名就是我们前面提到的文件。
MainPage类中没有实现随机改变颜色的逻辑。相应的它使用SecondPage来为它获得颜色信息。
下面是MainPage后台的代码:
Silverlight Project: SilverlightInsertData File: MainPage.xaml.cs (excerpt) public partial class MainPage : PhoneApplicationPage { public MainPage() { InitializeComponent(); } public Color? ReturnedColor { set; get; } void OnTextBlockManipulationStarted(object sender, ManipulationStartedEventArgs args) { this.NavigationService.Navigate(new Uri("/SecondPage.xaml", UriKind.Relative)); args.Complete(); args.Handled = true; } … } |
注意ReturnedColor 属性,可为空类型的Color属性和在前面App类中定义的属性一样。
下面是SecondPage后台的代码:
Silverlight Project: SilverlightInsertData File: SecondPage.xaml.cs (excerpt) public partial class SecondPage : PhoneApplicationPage { Random rand = new Random(); public SecondPage() { InitializeComponent(); } void OnTextBlockManipulationStarted(object sender, ManipulationStartedEventArgs args) { this.NavigationService.GoBack(); args.Complete(); args.Handled = true; } protected override void OnManipulationStarted(ManipulationStartedEventArgs args) { ContentPanel.Background = new SolidColorBrush( Color.FromArgb(255, (byte)rand.Next(255), (byte)rand.Next(255), (byte)rand.Next(255))); base.OnManipulationStarted(args); } protected override void OnNavigatedFrom(NavigationEventArgs args) { if (ContentPanel.Background is SolidColorBrush) { Color clr = (ContentPanel.Background as SolidColorBrush).Color; if (args.Content is MainPage) (args.Content as MainPage).ReturnedColor = clr; } base.OnNavigatedFrom(e); } } |
当点击SecondPage时,SecondPage就将随机改变它的背景颜色,当点击TextBlock时,GoBack方法被调用。 新写的代码在重载的OnNavigatedFrom方法中,它会在GoBack被调用后,立即被调用。如果有一个有效的SolidColorBrush,方法中会检查导向的对象类型是否为MainPage, 如果是,它会将当前的Color对象保存到MainPage的ReturnedColor属性中。
MainPage接着可以在它的OnNavigatedTo方法中获得这个属性的值:
Silverlight Project: SilverlightInsertData File: MainPage.xaml.cs (excerpt) public partial class MainPage : PhoneApplicationPage { … protected override void OnNavigatedTo(NavigationEventArgs args) { if (ReturnedColor != null) ContentPanel.Background = new SolidColorBrush(ReturnedColor.Value); base.OnNavigatedTo(args); } } |
从某种意义上说, MainPage调用SecondPage来获得Color值,就像调用一个对话框一样。但是如果你随后再次导向到SecondPage,它的屏幕初始颜色总是黑色(或者白色,如果你选择亮色彩的主题)。
有意思的是,SecondPage不能利用MainPage中的任何属性来初始化自己的背景颜色,因为目前我们没有重写SecondPage中的OnNavigatedTo 方法。从对称的角度,SecondPage需要定义自己的公共属性Color, 并需要MainPage在他的OnNavigatedFrom方法中设置这个Color属性值。你可能考虑对这个程序进行稍微地修改,在SecondPage中定义ReturnedColor属性。当MainPage导向到SecondPage,在MainPage的OnNavigatedFrom 方法中将SecondPage的实例对象保存到MainPage的一个成员变量中。当SecondPage结束,它将Color值保存到ReturnedColor属性中并且调用GoBack. MainPage中的OnNavigatedTo方法会被调用,在这个方法中,MainPage可以使用先前保存的SecondPage的对象实例来访问ReturnedColor属性值。这个方案听起来不错,在这个程序中是可行的。但需要特别注意的是MainPage不能保证这个导向到的SecondPage实例和将来导向回来的SecondPage实例是相同的实例。每一次从MainPage导向到SecondPage, SecondPage都会生成一个完新的实例。你将会在后面章节中近一步的理解到这一点。