建立可扩展的silverlight 应用框架 step-6

整理导航模块“LeftNav”

 

首先说一下我想要实现的效果。
我希望在左侧的导航点击了以后右侧的主体部分发声变化。

 

之前我在LeftNav模块用的控件是ToggleButton并为其制作了样式。本来想的是自己根据ToggleButton作为基础自己在做一个复合控件出来。不过这里做导航的话,ListBox会更加的适合些。ListBox的样式制作和之前的ToggleButton样式制作大同小异,都是一个原则:各个VisualStateGroup中的视图状态是可以共存的,VisualStateGroup内部的视图状态只能同时出现一个,尽量不要在多个VisualStateGroup同时改变同一个元素的属性。

 

下来导航模块“LeftNav”需要从外部加载导航配置文件文件"Nav.xml",将其获得的数据解析并于ListBox做数据绑定。要完成上诉的工作就需要引入Services模块,将各个功能分离开、各司其职。

Nav.xml:

<?xml version="1.0" encoding="utf-8" ?>
<root>
  <module showname="Hello Prism" xapname="OperatingTableTestModule" ViewType="OperatingTableTestModule.Views.HelloPrismView, OperatingTableTestModule, Version=1.0.0.0" />
  <module showname="欢迎" xapname="OTWelcomeModule" ViewType="OTWelcomeModule.Views.OTWelcomeView, OTWelcomeModule, Version=1.0.0.0" />
  <module showname="CGArt" xapname="OTCGArtModule" ViewType="OT.SL.CGArt2010.Style.Issue._31.Views.OTCGArtView, OT.SL.CGArt2010.Style.Issue.31, Version=1.0.0.0" />
  <module showname="妄摄写真" xapname="OTMosatsu" ViewType="OTMosatsu.Views.OTMosatsuView, OTMosatsu, Version=1.0.0.0" />  
</root>

 

这里先定义一个导航的实体类,“LdModule”
namespace OTLeftNavModule.Entities
{
    public class LdModule
    {
        //显示名称
        public string showname { get; set; }
        //View类别
        public string ViewType { get; set; }
        //Module的名称
        public string xapname { get; set; }
    }
}


service获取数据并解析

namespace OTLeftNavModule.Services
{
    public interface ILeftNavService
    {
        void RetrievLdModules(Action<IEnumerable<LdModule>> RetrievLdModulesCallBack);
    }
}
namespace OTLeftNavModule.Services
{
    public class LeftNavService : ILeftNavService
    {


        #region ILeftNavService Members

        /// <summary>
        /// 回调函数,用来介绍返回的LdModule
        /// </summary>
        /// <param name="RetrievLdModulesCallBack"></param>
        public void RetrievLdModules(Action<IEnumerable<LdModule>> RetrievLdModulesCallBack)
        {
            var uri = new Uri(HtmlPage.Document.DocumentUri, "Nav.xml");
            WebClient wb = new WebClient();
            wb.DownloadStringCompleted += (sender, e) => RetrievLdModulesCallBack(BuildLdModules(e));
            wb.DownloadStringAsync(uri);
        }

        /// <summary>
        /// 解析XML
        /// </summary>
        /// <param name="e"></param>
        /// <returns></returns>
        private IEnumerable<LdModule> BuildLdModules(DownloadStringCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                return new List<LdModule> { new LdModule() { showname = "error", ViewType = "error" } };
            }
            XDocument xmlLdModules = XDocument.Parse(e.Result);

            var ldmodules = from module in xmlLdModules.Descendants("module")
                            select new LdModule
                            {
                                showname = (string)module.Attribute("showname"),
                                ViewType = (string)module.Attribute("ViewType"),
                                xapname = (string)module.Attribute("xapname")
                            };
            return ldmodules;
        }

        #endregion
    }
}


将获取的数据赋给Model类用来做数据绑定

namespace OTLeftNavModule.Models
{
    public class LeftNavModel : INotifyPropertyChanged  
    {
        ILeftNavService leftNavService;
        public LeftNavModel(ILeftNavService leftNavService)
        {

            ldModules = new ObservableCollection<LdModule>();

            this.leftNavService = leftNavService;
            this.leftNavService.RetrievLdModules(OnRetrievLdModulesComplete);
        }

        /// <summary>
        /// 回调函数,为ldModules赋值
        /// </summary>
        /// <param name="newLdModules"></param>
        private void OnRetrievLdModulesComplete(IEnumerable<LdModule> newLdModules)
        {
            this.ldModules.Clear();
            foreach (var module in newLdModules)
            {
                this.ldModules.Add(module);
            }
        }

        public ObservableCollection<LdModule> ldModules
        {
            get;
            private set;
        }


        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;
        #endregion
    }
}


在Xaml里做绑定
	<ListBox Background="{x:Null}" x:Name="ListNav" BorderBrush="{x:Null}" ItemsSource="{Binding ldModules}" Foreground="Black" Style="{StaticResource NavListBoxStyle}" BorderThickness="0" ItemContainerStyle="{StaticResource NavListBoxItemStyle}" FontSize="13.333" Cursor="Hand" Margin="0,2,0,0">
        <ListBox.ItemTemplate>
            <DataTemplate><TextBlock Text="{Binding showname}"/></DataTemplate>
        </ListBox.ItemTemplate>
	</ListBox>  


最后需要替换右侧的主体Module了,我研究了Composite的Module模块、了解了Module生命周期。需要做到替换主体部分的思路就是先从主体区域得到当前Module,将其移除再载入新的Module。这样会比较适合我当前的项目。

        void ListNav_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            LdModule model = ListNav.SelectedItem as LdModule;

            //获取选中模块View的类型
            Type viewType = Type.GetType(model.ViewType, false);

            //是否增加被加载过
            if (viewType != null)
            {
                var resolveView = this.container.Resolve(viewType);

                IRegion mainRegion = this.regionManager.Regions["MainRegion"];

                //获取主体当前的View
                object view = mainRegion.GetView("mainCurrView");

                //移除
                if (view != null)
                    mainRegion.Remove(view);

                //载入新的View
                mainRegion.Add(resolveView, "mainCurrView");
            }
            else
            {
                //新加载Module并自动替换当前视图
                moduleManager.LoadModule(model.xapname);
            
            }
        }
作者:Nasa 
文章出处:我和未来有约会 (http://nasa.cnblogs.com/
版权声明:本文的版权归作者与博客园共有。转载时须注明本文的详细链接,否则作者将保留追究其法律责任。
 
posted @ 2010-03-03 17:06  王喆(nasa)  阅读(1378)  评论(0编辑  收藏  举报