Prism之Region(1)中,介绍了一些Prism中页面组织以及切换的方式。这一篇将以一个很简单的示例程序来实践一下。

源码下载

下面是效果图:

image

先说Log,Prism内置了ILogFacade接口,在Prism提供的QuickStart项目里的Modularity中,有一个CallbackLogger,这里我们直接拿过来使用。然后在PrismRegionShell中放一个TextBox,将log的内容显示在这个TextBox中。值得一提的是,为了让输出新log的直接显示出来,需要将TextBox的滚动条滚动到最下面。这里采用的是如下方法:

public void Log(string message, Category category, Priority priority)
{
    this.LogContainer.Text += string.Format(CultureInfo.CurrentUICulture, "[{0}][{1}] {2}\r\n", category, priority, message);
    //  这段代码的作用是让文本框的滚动条滚动到最底部
    LogContainer.Select(LogContainer.Text.Length, LogContainer.Text.Length);
}

然后说一下左边的导航区。这里放置了一个ItemsControl,并将其设为Region。里面的两个按钮并不是直接写死到xaml里的,而是在两个Module初始化时动态添加进来的。也就是说,这个ItemsControl并不知道自己将要包含哪些项。这里我们使用IRegionManager.RegisterViewWithRegion(RegionNames.NavRegion, typeof(EmptyNavigationItem));这种方式来将视图注册到Region中。这样当该Region显示的时候两个视图才会被初始化。这里需要注意的是,一个Region里需要同时显示多个视图时,视图的顺序问题。比如ItemsControl,哪个先被注册就哪个显示在上面,但是由于Module的加载速度等原因,所以这时两个视图不一定谁在上面。现在我需要指定[导航示例]这个按钮在上,那么Prism为我们提供了ViewSortHintAttribute来解决这个问题。在需要进行排序的视图上添加上相应的attribute就可以了。

[ViewSortHint("01")]
public partial class NavigationItem : UserControl

[ViewSortHint("02")]
public partial class EmptyNavigationItem : UserControl

在初始化导航实例的Module时,将导航示例的视图注册到内容区的Region,这时[上一个]按钮依然处于灰色状态,因为通过RegisterViewWithRegion方法显示的页面是不被记录的。当点击[ViewA][ViewB][ViewC]这三个按钮时,会采用RequestNavigate方法来进行页面的跳转,这时页面跳转的过程会被记录下来,此时就可以通过[上一个]和[下一个]按钮进行页面的前进和后退。

void ToSpecifiedView(string viewName)
{
    UriQuery query = new UriQuery();
    if (viewName == ViewNames.ViewA)
    {
        query.Add("Time", DateTime.Now.ToShortTimeString());
    }
    Uri uri = new Uri(viewName + query.ToString(), UriKind.Relative);
    _regionManager.RequestNavigate(RegionNames.NavDemoShowRegion, uri);
    logger.Log("跳转到视图 [" + viewName + "]", Category.Info, Priority.Low);
    ResetNavigationButtonState();
}

注意这三个视图已经在初始化Module的时候使用IUnityContainer.RegisterType<object, ViewA>(ViewNames.ViewA)方法注册过了。

public void Initialize()
{
    logger.Log("初始化Navigation模块", Category.Debug, Priority.Low);
    _regionManager.RegisterViewWithRegion(RegionNames.NavRegion, typeof(NavigationItem));
    _regionManager.RegisterViewWithRegion(RegionNames.MainRegion, 
                                            () => _container.Resolve<NavigationContainer>() );
    _regionManager.RegisterViewWithRegion(RegionNames.NavDemoActionRegion, typeof(ActionController));

    //  注意注册的类型的必须是object,因为Prism无法确定视图的类型,所以就用了object
    _container.RegisterType<object, ViewA>(ViewNames.ViewA);
    _container.RegisterType<object, ViewB>(ViewNames.ViewB);
    _container.RegisterType<object, ViewC>(ViewNames.ViewC);
}

ViewA和ViewB都实现了INavigationAware接口,不同之处在于ViewA是在其对应的ViewModel ViewAViewModel类中实现的,而ViewB则直接在Code Behind中实现的。Prism对MVVM提供了良好的支持,因此既可以选择在视图中实现该接口也可以在对应的ViewModel中实现。

public bool IsNavigationTarget(NavigationContext navigationContext)
{
    return false;
}

在ViewB中,IsNavigationTarget方法返回了false,而ViewA中则返回了true。可以通过点击三个按钮进行页面跳转,观察log可以发现,ViewA只创建了一次,而ViewB则每次都要重新创建。还有就是在跳转到ViewA的时候传递了参数,可以在OnNavigatedTo方法中取出参数。

public void OnNavigatedTo(NavigationContext navigationContext)
{
    UriQuery query = navigationContext.Parameters;
    string time = query["Time"];
    logger.Log(string.Format("ViewA: 现在时间 {0}", time), Category.Info, Priority.Medium);
}

源码下载

posted on 2011-02-10 13:25  Jason Li  阅读(6625)  评论(6编辑  收藏