• SilverLight之路(三)


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

    效果如下

     

    结果页

     

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

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

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

     

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

     

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

     

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

    现在回到我们的主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页面并加载到主应用程序中的指定位置。这个实现在网上资源好多,详细过程可以去搜索一下。

     

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

     

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

     

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

    模块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 });

    }

     

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

     

      

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

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

  • 相关阅读:
    【转】对象持久化与数据序列化的联系?
    【转】Linux安装方法一(U盘引导)
    bash中的"-n"、"-z" 以及“[]” 、“[[]]”判断
    mysql获取行号
    IP白名单
    复合赋值位运算符“&=、| =”
    Java匿名内部类访问外部
    mysql的orde by 按照指定状态顺序排序
    Spring声明式事务
    定时任务总结
  • 原文地址:https://www.cnblogs.com/meteortent/p/2076276.html
Copyright © 2020-2023  润新知