建立可扩展的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);
            
            }
        }   

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏一个会写诗的程序员的博客

React State(状态): React通过this.state来访问state,通过this.setState()方法来更新stateReact State(状态)

React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。 React 里...

1393
来自专栏Ryan Miao

照着官方文档学习react

准备 先要准备环境。搭建一个基于webpack的react环境:Hello ReactJS. 一些要点 我在想是否应该完整的记录照抄的过程呢。毕竟已经开始一段,...

3707
来自专栏python_lwx

新手请教python抽奖程序

大家好,我开始学python,想做一个抽奖程序,源代码如下,如果我要在框架内加上1等奖1个人 ,2等奖2个人,三等奖3个人 应该怎么样编写相关联的代码,就是点击...

5434
来自专栏.NET开发者社区

C#Winform使用扩展方法自定义富文本框(RichTextBox)字体颜色

在利用C#开发Winform应用程序的时候,我们有可能使用RichTextBox来实现实时显示应用程序日志的功能,日志又分为:一般消息,警告提示 和错误等类别。...

3136
来自专栏阮一峰的网络日志

React 测试入门教程

越来越多的人,使用React开发Web应用。它的测试就成了一个大问题。 React的组件结构和JSX语法,不适用传统的测试工具,必须有新的测试方法和工具。 本文...

3514
来自专栏老马寒门IT

jQuery EasyUI 详解

easyui 为创建现代化,互动,JavaScript 应用程序,提供必要的功能。

4691
来自专栏菩提树下的杨过

Flash/Flex学习笔记(4):如何打开网页及Get/Post数据

flash终究只是客户端技术,所以很多时候还是需要与服务端技术(比如asp,asp.net,jsp,php之类)进行数据交互的,下面的代码演示了如何在flash...

2357
来自专栏听雨堂

电子签名实现的思路、困难及解决方案

        在办公自动化的流程中希望实现电子签名。         思路:             1、图片的存放:安全起见存放在库中为宜。最好不能被轻易下...

2595
来自专栏james大数据架构

在ASPNET中使用JS集锦

(一).确认删除用法: 1. BtnDel.Attributes.Add("onclick","return confirm('"+"确认删除?"+"')")...

2217
来自专栏令仔很忙

机房收费系统——VB将MSHflexgrid控件中的数据导出为Excel

 在做机房收费系统的时候,许多窗体用到的一个功能,就是将从数据库中提取出来的数据导出到Excel中。

861

扫码关注云+社区

领取腾讯云代金券