建立可扩展的silverlight 应用框架 step-6:整理导航模块“LeftNav”
首先说一下我想要实现的效果。
我希望在左侧的导航点击了以后右侧的主体部分发声变化。
之前我在LeftNav模块用的控件是ToggleButton并为其制作了样式。本来想的是自己根据 ToggleButton作为基础自己在做一个复合控件出来。不过这里做导航的话,ListBox会更加的 适合些。ListBox的样式制作和之前的ToggleButton样式制作大同小异,都是一个原则:各个 VisualStateGroup中的视图状态是可以共存的,VisualStateGroup内部的视图状态只能同时 出现一个,尽量不要在多个VisualStateGroup同时改变同一个元素的属性。
下来导航模块“LeftNav”需要从外部加载导航配置文件文件"Nav.xml",将其获得的数据 解析并于ListBox做数据绑定。要完成上诉的工作就需要引入Services模块,将各个功能分离 开、各司其职。
Nav.xml:
1 <?xml version="1.0" encoding="utf-8" ?>
2 <root>
3 <module showname="Hello Prism" xapname="OperatingTableTestModule" ViewType="OperatingTableTestModule.Views.HelloPrismView, OperatingTableTestModule, Version=1.0.0.0" />
4 <module showname="欢迎" xapname="OTWelcomeModule" ViewType="OTWelcomeModule.Views.OTWelcomeView, OTWelcomeModule, Version=1.0.0.0" />
5 <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" />
6 <module showname="妄摄写真" xapname="OTMosatsu" ViewType="OTMosatsu.Views.OTMosatsuView, OTMosatsu, Version=1.0.0.0" />
7 </root>
这里先定义一个导航的实体类,“LdModule”
01 namespace OTLeftNavModule.Entities
02 {
03 public class LdModule
04 {
05 //显示名称
06 public string showname { get; set; }
07 //View类别
08 public string ViewType { get; set; }
09 //Module的名称
10 public string xapname { get; set; }
11 }
12 }service获取数据并解析
1 namespace OTLeftNavModule.Services
2 {
3 public interface ILeftNavService
4 {
5 void RetrievLdModules(Action<IEnumerable<LdModule>> RetrievLdModulesCallBack);
6 }
7 }
01 namespace OTLeftNavModule.Services
02 {
03 public class LeftNavService : ILeftNavService
04 {
05
06
07 #region ILeftNavService Members
08
09 /// <summary>
10 /// 回调函数,用来介绍返回的 LdModule
11 /// </summary>
12 /// <param name="RetrievLdModulesCallBack"></param>
13 public void RetrievLdModules(Action<IEnumerable<LdModule>> RetrievLdModulesCallBack)
14 {
15 var uri = new Uri(HtmlPage.Document.DocumentUri, "Nav.xml");
16 WebClient wb = new WebClient();
17 wb.DownloadStringCompleted += (sender, e) => RetrievLdModulesCallBack(BuildLdModules(e));
18 wb.DownloadStringAsync(uri);
19 }
20
21 /// <summary>
22 /// 解析XML
23 /// </summary>
24 /// <param name="e"></param>
25 /// <returns></returns>
26 private IEnumerable<LdModule> BuildLdModules(DownloadStringCompletedEventArgs e)
27 {
28 if (e.Error != null)
29 {
30 return new List<LdModule> { new LdModule() { showname = "error", ViewType = "error" } };
31 }
32 XDocument xmlLdModules = XDocument.Parse(e.Result);
33
34 var ldmodules = from module in xmlLdModules.Descendants ("module")
35 select new LdModule
36 {
37 showname = (string)module.Attribute("showname"),
38 ViewType = (string)module.Attribute ("ViewType"),
39 xapname = (string)module.Attribute("xapname")
40 };
41 return ldmodules;
42 }
43
44 #endregion
45 }
46 }将获取的数据赋给Model类用来做数据绑定
01 namespace OTLeftNavModule.Models
02 {
03 public class LeftNavModel : INotifyPropertyChanged
04 {
05 ILeftNavService leftNavService;
06 public LeftNavModel(ILeftNavService leftNavService)
07 {
08
09 ldModules = new ObservableCollection<LdModule>();
10
11 this.leftNavService = leftNavService;
12 this.leftNavService.RetrievLdModules(OnRetrievLdModulesComplete);
13 }
14
15 /// <summary>
16 /// 回调函数,为ldModules赋值
17 /// </summary>
18 /// <param name="newLdModules"></param>
19 private void OnRetrievLdModulesComplete(IEnumerable<LdModule> newLdModules)
20 {
21 this.ldModules.Clear();
22 foreach (var module in newLdModules)
23 {
24 this.ldModules.Add (module);
25 }
26 }
27
28 public ObservableCollection<LdModule> ldModules
29 {
30 get;
31 private set;
32 }
33
34
35 #region INotifyPropertyChanged Members
36
37 public event PropertyChangedEventHandler PropertyChanged;
38 #endregion
39 }
40 }在Xaml里做绑定
1 <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">
2 <ListBox.ItemTemplate>
3 <DataTemplate><TextBlock Text="{Binding showname}"/></DataTemplate>
4 </ListBox.ItemTemplate>
5 </ListBox>
最后需要替换右侧的主体Module了,我研究了Composite的Module模块、了解了Module生 命周期。需要做到替换主体部分的思路就是先从主体区域得到当前Module,将其移除再载入 新的Module。这样会比较适合我当前的项目。
01 void ListNav_SelectionChanged(object sender, SelectionChangedEventArgs e)
02 {
03 LdModule model = ListNav.SelectedItem as LdModule;
04
05 //获取选中模块View的类型
06 Type viewType = Type.GetType(model.ViewType, false);
07
08 //是否增加被加载过
09 if (viewType != null)
10 {
11 var resolveView = this.container.Resolve(viewType);
12
13 IRegion mainRegion = this.regionManager.Regions["MainRegion"];
14
15 //获取主体当前的View
16 object view = mainRegion.GetView("mainCurrView");
17
18 //移除
19 if (view != null)
20 mainRegion.Remove(view);
21
22 //载入新的View
23 mainRegion.Add(resolveView, "mainCurrView");
24 }
25 else
26 {
27 //新加载Module并自动替换当 前视图
28 moduleManager.LoadModule (model.xapname);
29
30 }
31 }