SilverLight之路(三)

我们先以“风险测试”这一模块入手吧,这个模块功能相对比较简单,业务逻辑很清楚,做题,得分,出结果

效果如下

 SilverLight之路(三)

结果页

 SilverLight之路(三)

看似简单,但这里牵涉到的知识点可不少,比如ItemControls控件的使用,Chart控件的使用,程序集的动态加载,资源的应用程序级(是程序级别,不是程序集)共享等,可能在一篇里说不完,不怕,那就一步一步来吧。

在开始这一模块之前,先来整理一下我思路。我们的“项目”计划是使用全站SL,这样的话,如果全部功能都在一个项目中,那最终可能会使我们的XAP灰常巨大,如果访问一个页面是要等上几分钟的话,你认为我们的用户会有那么多的耐心吗?好的做法应该是各模块分开,按需加载。

既然如此,不用多想,再在我们的解决方案中新建一个项目,如下

 SilverLight之路(三)

在接下来的对话框中会询问在哪个网站上承载新建的sl应用程序

 SilverLight之路(三)

我们选择默认,并去掉生成测试页的选项,这样VS2010自动找到了我们解决方案中的网站项目,并添加了进去。按F6重新编译后可以看到,现在我们的项目结构如下

 SilverLight之路(三)

接下来我们要做的,就是把我们这几个项目连通,界面流程为:启动,显示登录界面,加载主界面,显示风险测试模块。

现在回到我们的主SL应用程序,也就是TFT-WebFirst-SL中,现在我们有了login页与mainpage页,之前为了显示login效果,我们在mainpage页里简单的把login页里show了出来,但现在需要改改了,很明显,我们现在缺少一个“容器”页,即用来在login与mainpage之间切换的父容器,我们新建一个Index页。(这可以在vs中操作也可以在blend中操作,但他们之间往往不同即时同步,比如我们新加了一个页面,如果马上打开blend就会看不到,如果在blend中新加了一个元素或命名了一个元素,同样无法在vs中马上反映出来,这时只要用vs编译一下即可)

相关代码类似如下

App.xaml.cs

  
    
private void Application_Startup( object sender, StartupEventArgs e)

{

// this.RootVisual = new MainPage();

this .RootVisual = new Index();

}

Index.xaml.cs

 

  
    
void Index_Loaded( object sender, RoutedEventArgs e)
{
Login l
= new Login();
l.ParentPage
= this ;
this .Content = l;
}

public void GoToMainPage()
{
this .Content = new MainPage();
}

 

Login.xaml.cs

  
    
public Index ParentPage { get ; set ; }



void btnLogin_Click( object sender, RoutedEventArgs e)

{

ParentPage.GoToMainPage();

}

注:该项目主要以学习sl为目的,因此没有使用任何开发模式,代码实现上以也以简单实现功能为主

接下来,我们动态加载风险测试模块

主要代码如下

 

  
    
/// <summary>

/// 从XAP包中返回程序集信息(该方法来源网上)

/// </summary>

/// <param name="packageStream"></param>

/// <param name="assemblyName"></param>

/// <returns></returns>

public Assembly GetAssemblyFromXap(Stream packageStream, String assemblyName)

{

Stream stream
= Application.GetResourceStream( new StreamResourceInfo(packageStream, null ), new Uri( " AppManifest.xaml " , UriKind.Relative)).Stream;

Assembly asm
= null ;

XmlReader xmlReader
= XmlReader.Create(stream);

xmlReader.MoveToContent();

if (xmlReader.ReadToFollowing( " Deployment.Parts " ))

{

string str = xmlReader.ReadInnerXml();

Regex reg
= new Regex( " x:Name=\"(.+?)\" " );

Match match
= reg.Match(str);

string sName = "" ;

if (match.Groups.Count == 2 )

{

sName
= match.Groups[ 1 ].Value;

}

reg
= new Regex( " Source=\"(.+?)\" " );

match
= reg.Match(str);

string sSource = "" ;

if (match.Groups.Count == 2 )

{

sSource
= match.Groups[ 1 ].Value;

}

AssemblyPart assemblyPart
= new AssemblyPart();

StreamResourceInfo streamInfo
= Application.GetResourceStream( new StreamResourceInfo(packageStream, " application/binary " ), new Uri(sSource, UriKind.Relative));

if (sSource == assemblyName)

{

asm
= assemblyPart.Load(streamInfo.Stream);

}

}

return asm;

}

}

void LoadRiskTest()

{
// 加载风险测试模块

WebClient rtwc
= new WebClient();

rtwc.OpenReadCompleted
+= new OpenReadCompletedEventHandler(

(s, ex)
=>

{

Assembly assembly
= da.GetAssemblyFromXap(ex.Result, " RiskTest.dll " );

UIElement element
= assembly.CreateInstance( " RiskTest.MainPage " ) as UIElement;

this .BorderMainPanel.Child = element; // 这里使用Border做为容器,是因为动态加载控件时,使用Canvas不能自适应大小

});

Uri xapUri
= new Uri(HtmlPage.Document.DocumentUri, " ClientBin/RiskTest.xap " );

rtwc.OpenReadAsync(xapUri);

}

 

具体思路是通过WebClient到网站的ClientBin目录中下载RiskTest.xap包,然后通过读取其中的清单文件(AppManifest.xaml),加载该模块的主程序集(RiskTest.dll),然后通过反射创建其中的MainPage页面并加载到主应用程序中的指定位置。这个实现在网上资源好多,详细过程可以去搜索一下。

 

这样,我们的流程就算是完成了,现在运行应该就可以看到动态加载后的效果了,只不过现在我们的风险测试模块没有内容

 

现在我们来看看风险测试模块的界面布局,我们注意到在每个模块下都有一个左边的导航功能,如

 SilverLight之路(三)

但这里面又分上下两部分,显然,下半部分为各模块内部功能的导航,上半部分在每个模块中是一样的,因此,上半部分不应放到模块中,应该在主程序中实现。既然如此,那我们就需要在各模块的这一部分保留一个位置,在主程序加载各模块后再把主程序中的“用户信息”部分加进去,简单实现为在各模块的主界面中提供一个方法,并在主程序集中调用,实现代码如

模块mainpage.xaml.cs

 

  
    
public void FillUserInfoCtr(UserControl uc)

{

this .BorderUserInfo.Child = uc;

}

 

主程序调用时

 

  
    
void LoadRiskTest()

{
// 加载风险测试模块

WebClient rtwc
= new WebClient();

rtwc.OpenReadCompleted
+= new OpenReadCompletedEventHandler(

(s, ex)
=>

{

Assembly assembly
= da.GetAssemblyFromXap(ex.Result, " RiskTest.dll " );

UIElement element
= assembly.CreateInstance( " RiskTest.MainPage " ) as UIElement;

this .BorderMainPanel.Child = element;

LoadUserInfo(element);

});

Uri xapUri
= new Uri(HtmlPage.Document.DocumentUri, " ClientBin/RiskTest.xap " );

rtwc.OpenReadAsync(xapUri);

}



void LoadUserInfo(UIElement element)

{
// 为各模块加载用户信息

UserInfo ui
= new UserInfo();

Type t
= element.GetType();

MethodInfo mi
= t.GetMethod( " FillUserInfoCtr " );

mi.Invoke(element,
new object [] { ui });

}

 

风险测试模块的主界面布局类似

 SilverLight之路(三)

SilverLight之路(三)

  

BorderUserInfo就是用来加载主程序中的用户信息部分的容器

SVMain是该模块中各功能页面的展示区

你可能感兴趣的:(silverlight)