Silverlight MVVM 贴近实战(二)

上篇我们看了登陆界面,本篇我对服务端进行一个剖析。以及主界面的设计。我们上次忘记解释一个Silverlight的项目如何寄宿在MVC项目上。我们先来看看如何寄宿。看下图

我们看到了MISInfoManage这个项目是一个Silverlight项目。它寄宿在MISInfomanage.Web.Host这个MVC3项目中。流程是这样的,Silverlight寄宿在MISInfomanage.Web.Host上,MISInfomanage.Web.Host这个项目它的启动路径如下图所示,是Home/Index,完整路径就是Http://localhost:port/Home/Index

我们来看看控制器代码

 
 
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Web;  
  5. using System.Web.Mvc;  
  6.  
  7. namespace MISInfoManage.Web.Controllers  
  8. {  
  9.     public class HomeController : Controller  
  10.     {  
  11.         //  
  12.         // GET: /Index/  
  13.         public ActionResult Index()  
  14.         {  
  15.             return View("~/Views/Index.cshtml");  
  16.         }  
  17.     }  
  18. }  

当项目运行起来后,直接将页面导航至Index.chtml。所以到这里大家应该能想来Silverlight就寄宿在这个界面上。我们看看代码是如何寄宿的。

 
 
  1. @{  
  2.     Layout = null;  
  3. }  
  4. <!DOCTYPE html> 
  5. <html> 
  6. <head> 
  7.     <title>Index1</title> 
  8.     <style type="text/css"> 
  9.     html, body  
  10.     {  
  11.         height: 100%;  
  12.         overflow: auto;  
  13.     }  
  14.  
  15.     body  
  16.     {  
  17.         padding: 0;  
  18.         margin: 0;  
  19.     }  
  20.  
  21.     #silverlightControlHost  
  22.     {  
  23.         height: 100%;  
  24.         text-align: center;  
  25.     }  
  26. </style> 
  27.     <script type="text/javascript" src="../../Silverlight.js"></script> 
  28.     <script type="text/javascript"> 
  29.     function onSilverlightError(sender, args) {  
  30.         var appSource = "";  
  31.         if (sender != null && sender != 0) {  
  32.             appSource = sender.getHost().source;  
  33.         }  
  34.  
  35.         var errorType = args.ErrorType;  
  36.         var iErrorCode = args.ErrorCode;  
  37.  
  38.         if (errorType == "ImageError" || errorType == "MediaError") {  
  39.             return;  
  40.         }  
  41.  
  42.         var errMsg = "Silverlight 应用程序中未处理的错误 " + appSource + "\n";  
  43.  
  44.         errMsg += "代码: " + iErrorCode + "    \n";  
  45.         errMsg += "类别: " + errorType + "       \n";  
  46.         errMsg += "消息: " + args.ErrorMessage + "     \n";  
  47.  
  48.         if (errorType == "ParserError") {  
  49.             errMsg += "文件: " + args.xamlFile + "     \n";  
  50.             errMsg += "行: " + args.lineNumber + "     \n";  
  51.             errMsg += "位置: " + args.charPosition + "     \n";  
  52.         }  
  53.         else if (errorType == "RuntimeError") {  
  54.             if (args.lineNumber != 0) {  
  55.                 errMsg += "行: " + args.lineNumber + "     \n";  
  56.                 errMsg += "位置: " + args.charPosition + "     \n";  
  57.             }  
  58.             errMsg += "方法名称: " + args.methodName + "     \n";  
  59.         }  
  60.  
  61.         引发新错误(errMsg);  
  62.     }  
  63.     </script> 
  64. </head> 
  65. <body> 
  66.     <form id="form1" runat="server" style="height: 100%"> 
  67.     <div id="silverlightControlHost"> 
  68.         <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" 
  69.             width="100%" height="100%"> 
  70.             <param name="source" value="/ClientBin/MISInfoManage.xap" /> 
  71.             <param name="onError" value="onSilverlightError" /> 
  72.             <param name="background" value="white" /> 
  73.             <param name="minRuntimeVersion" value="4.0.50826.0" /> 
  74.             <param name="autoUpgrade" value="true" /> 
  75.             <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50826.0" style="text-decoration: none"> 
  76.                 <img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="获取 Microsoft Silverlight" 
  77.                     style="border-style: none" /> 
  78.             </a> 
  79.         </object> 
  80.           
  81.     </div> 
  82.     </form> 
  83. </body> 
  84. </html> 

关键就在于Silverlight.js的引用,以及object中param的设置。在这里需要注意的是这个source属性,它的value值是指xap包所在的位置,如下所示,位于ClientBin下。

光凭这些代码还不能完成寄宿,我们还需要在MISInfomanage.Web.Host上点击右键,选择Silverlight Applications。添加要寄宿的Silverlight项目,如下

OK,这样就完成了一个Silverlight项目的寄宿。谈完这个,我们再回到Server端机构的解析,我就以一个登陆流程来解释。首先用户登录界面点击登陆按钮,调用Login/GetUser/{id}。

 
 
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Web;  
  5. using System.Web.Mvc;  
  6.  
  7. namespace MISInfoManage.Web.Controllers  
  8. {  
  9.     using Server.Business.Interface;  
  10.     using Server.Domain;  
  11.     using Server.Model.edmx;  
  12.     public class LoginController : Controller  
  13.     {  
  14.         //  
  15.         // GET: /Login/  
  16.         IUserBiz userBiz;  
  17.         public LoginController(IUserBiz userBiz)  
  18.         {  
  19.             this.userBiz = userBiz;  
  20.         }  
  21.  
  22.         public JsonResult GetUser(string id)  
  23.         {  
  24.             Users user = userBiz.GetUser(id);  
  25.             return Json(user, JsonRequestBehavior.AllowGet);  
  26.         }  
  27.     }  
  28. }  

这个时候,程序要调用UserBiz,UserBiz要调用UserService,UserService要调用UserRepository,而UserRepository又继承BaseRepository<T>,在每一层调用都有IOC存在。IOC怎么工作呢,先看看Global.asax.cs。

 
 
  1. protected void Application_Start()  
  2.         {  
  3.             AreaRegistration.RegisterallAreas();  
  4.             IoCHelper.InitializeWith(new DependencyResolverFactory());  
  5.             ControllerBuilder.Current.SetControllerFactory(new ResolverControllerFactory().GetControllerFactory());  
  6.             RegisterRoutes(RouteTable.Routes);  
  7.         } 

Controller的创建已经交由DependencyResolverFactory这个依赖注入工厂接手,所以我们看到Controller中的IUserBiz而不是UserBiz。那么这个注入在哪里配置着呢?在Host项目下,如下图所示

就是这个Unity.Login.Config。因为目前我只做了个登陆功能,所以在这里只有一个Config文件。那么Unity是怎么读取这个配置文件的呢?我们看看Server端IOC项目下有个UnityContainerBuilder类,他是负责创建依赖注入容器的。在它里面有这么一段代码

 
 
  1. private IEnumerable<string> GetConfigFilePaths()  
  2.         {  
  3.             string path = AppSettingsHelper.GetString("UnityConfigPath""Config/Unity");// 认值为"Config/Unity"  
  4.             return Directory.GetFiles(PathHelper.LocateServerPath(path))  
  5.                 .Where(fullName => Path.GetExtension(fullName).Equals(".config", StringComparison.CurrentCultureIgnoreCase));  
  6.         } 

就是这个方法来抓取所有的注入配置文件。我们来看看注入配置文件

 
 
  1. <?xml version="1.0"?> 
  2. <configuration> 
  3.   <configSections> 
  4.     <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/> 
  5.   </configSections> 
  6.   <unity> 
  7.     <typeAliases> 
  8.       <typeAlias alias="IUserRepository" type="Server.Repository.Interface.IUserRepository, Repository" /> 
  9.       <typeAlias alias="UserRepository" type="Server.Repository.Implement.UserRepository, Repository" /> 
  10.       <typeAlias alias="IUserService" type="Server.Application.Interface.IUserService,Application" /> 
  11.       <typeAlias alias="UserService" type="Server.Application.Implement.UserService, Application" /> 
  12.       <typeAlias alias="IUserBiz" type="Server.Business.Interface.IUserBiz,Business" /> 
  13.       <typeAlias alias="UserBiz" type="Server.Business.Implement.UserBiz, Business" /> 
  14.  
  15.       <typeAlias alias="IDatabaseFactory" type="Server.Domain.IDatabaseFactory, Domain" /> 
  16.       <typeAlias alias="DatabaseFactory" type="Server.Domain.DatabaseFactory,Domain" /> 
  17.       <!--控制器 开始--> 
  18.       <typeAlias alias="IControllerFactory" type="System.Web.Mvc.IControllerFactory, System.Web.Mvc,Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> 
  19.       <typeAlias alias="UnityControllerFactory" type="Server.IOC.IocResolver.UnityControllerFactory,IOC" /> 
  20.       <typeAlias alias="LoginController" type="MISInfoManage.Web.Controllers.LoginController, MISInfoManage.Web.Host" /> 
  21.       <!--控制器 结束--> 
  22.     </typeAliases> 
  23.  
  24.     <containers> 
  25.       <container name="ContainerEF"> 
  26.         <!--登录--> 
  27.         <register type="IDatabaseFactory" mapTo="DatabaseFactory"> 
  28.           <constructor> 
  29.             <param name="connectionName"> 
  30.               <value value="MISInfoEntities"></value> 
  31.             </param> 
  32.           </constructor> 
  33.         </register> 
  34.  
  35.         <register type="IUserRepository" mapTo="UserRepository"> 
  36.           <constructor> 
  37.             <param name="dataBaseFactory"> 
  38.               <dependency type="DatabaseFactory"></dependency> 
  39.             </param> 
  40.           </constructor> 
  41.         </register> 
  42.  
  43.         <register type="IUserService" mapTo="UserService"> 
  44.           <constructor> 
  45.             <param name="dataContext"> 
  46.               <dependency type="DatabaseFactory"></dependency> 
  47.             </param> 
  48.             <param name="userRepository"> 
  49.               <dependency type="UserRepository"></dependency> 
  50.             </param> 
  51.           </constructor> 
  52.         </register> 
  53.  
  54.         <register type="IUserBiz" mapTo="UserBiz"> 
  55.           <constructor> 
  56.             <param name="userService"> 
  57.               <dependency type="UserService"></dependency> 
  58.             </param> 
  59.           </constructor> 
  60.         </register> 
  61.  
  62.         <register type="IControllerFactory" mapTo="UnityControllerFactory"> 
  63.         </register> 
  64.  
  65.         <register type="LoginController" mapTo="LoginController"> 
  66.           <constructor> 
  67.             <param name="userBiz"> 
  68.               <dependency type="UserBiz"></dependency> 
  69.             </param> 
  70.           </constructor> 
  71.         </register> 
  72.       </container> 
  73.     </containers> 
  74.   </unity> 
  75. </configuration> 
  76.  

  <typeAlias alias="IUserService" type="Server.Application.Interface.IUserService,Application" /> 

这个配置是一个声明别名的配置,type制定其所在的完整命名空间,所在程序集。类似于这样的配置都一样。我们重点看ContanerEF中的配置。首先是IDatabaseFactory的配置。DataBaseFactory的代码如下

 
 
  1. public class DatabaseFactory : Idisposable, IDatabaseFactory  
  2.     {  
  3.         DbContext dbContext;  
  4.         string connectionName;  
  5.         public DatabaseFactory(string connectionName)  
  6.         {  
  7.             this.connectionName = connectionName;  
  8.         }  
  9.         public DbContext Get()  
  10.         {  
  11.             dbContext = new DbContext(connectionName);  
  12.             return dbContext;  
  13.         }  
  14.         public void dispose()  
  15.         {  
  16.             if (dbContext != null)  
  17.             {  
  18.                 dbContext.dispose();  
  19.             }  
  20.         }  
  21.     } 

在UserRepository中我们需要给BaseRepository传递一个databaseFactory,用来创建对应的DBContext。如下所示

 
 
  1. public class UserRepository : BaseRepository<Users>, IUserRepository  
  2.     {  
  3.         public UserRepository(IDatabaseFactory dataBaseFactory)  
  4.             : base(dataBaseFactory)  
  5.         { }  
  6.     } 

在这里,因为我们Login界面所用到的DbContext的链接字符串如下

 
 
  1. <connectionStrings> 
  2.     <add name="applicationservices" 
  3.          connectionString="data source=.\sqlEXPRESS;Integrated Security=sspI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true" 
  4.          providerName="System.Data.sqlClient" /> 
  5.     <add name="MISInfoEntities" connectionString="Metadata=res://*/edmx.MISInfo.csdl|res://*/edmx.MISInfo.ssdl|res://*/edmx.MISInfo.msl;provider=System.Data.sqlClient;provider connection string=&quot;data source=ZZCYIC6VXOK5UXO\MSsqlSERVER08;initial catalog=MISInfo;integrated security=True;multipleactiveresultsets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" /> 
  6.   </connectionStrings> 

所以注入的时候,我们把DatabaseFactory构造函数中的connectionName注入为MISInfoEntities。对于其他的注入参数,都是采用构造函数注入相信大家看看就清楚了。在最后我们看看BaseRepository的构造函数

 
 
  1. public BaseRepository(IDatabaseFactory dataBaseFactory)  
  2.         {  
  3.             context = dataBaseFactory.Get() as DbContext;  
  4.             context.Configuration.LazyLoadingEnabled = true;  
  5.         } 

由此我们可以看出,如果你的Databasefactory的connectionstring是MISInfoEntities的话,那么BaseRepository接收到的将会是MISInfoEntities(继承DbContext)。如果是PersonEntities,那么Databasefactory的Get方法获取的是PersonEntities(继承DbContext)。这样就可以根据配置文件很容易的更换数据源,或者有时候叫工作单元,从而实现低耦合和控制反转。好了,最后我们一起看看我设计的主界面。

 

ok,最后我们看看设计代码

 
 
  1. <UserControl 
  2.     x:Class="MISInfoManage.MainPage" 
  3.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"   
  4.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  5.     xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"   
  6.     xmlns:uriMapper="clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation" 
  7.     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"   
  8.     mc:Ignorable="d" 
  9.     xmlns:source="clr-namespace:MISInfoManage.Resources"> 
  10.     <UserControl.Resources> 
  11.         <source:MainPageResource x:Key="Resource"></source:MainPageResource> 
  12.     </UserControl.Resources> 
  13.     <Grid x:Name="LayoutRoot" Style="{StaticResource LayoutRootGridStyle}" > 
  14.         <Grid.Background> 
  15.             <ImageBrush ImageSource="/MISInfoManage;component/Images/windows.jpg" Stretch="UniformToFill"></ImageBrush> 
  16.         </Grid.Background> 
  17.         <Grid.RowDeFinitions> 
  18.             <RowDeFinition Height="*"></RowDeFinition> 
  19.             <RowDeFinition Height="Auto"></RowDeFinition> 
  20.         </Grid.RowDeFinitions> 
  21.         <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Grid.Row="0"> 
  22.             <StackPanel Orientation="Vertical" HorizontalAlignment="Left"> 
  23.                 <Border CornerRadius="5"  BorderBrush="Aqua" BorderThickness="0" MouseMove="Border_MouseMove" MouseLeave="Border_MouseLeave"> 
  24.                     <StackPanel Orientation="Vertical" x:Name="StackPanel1" Margin="10,10,10"> 
  25.                         <Image Source="/MISInfoManage;component/Images/Navigation/UserManage.png" Width="60"/> 
  26.                         <TextBlock x:Name="Tb_UserManage" Text="{Binding Tb_UserManage,Source={StaticResource Resource}}" Style="{StaticResource MainPageTextStyle}"/> 
  27.                     </StackPanel> 
  28.                 </Border> 
  29.                 <Border CornerRadius="5"  BorderBrush="Aqua" BorderThickness="0" MouseMove="Border_MouseMove" MouseLeave="Border_MouseLeave"> 
  30.                     <StackPanel Orientation="Vertical" Margin="10,10"> 
  31.                         <Image Source="/MISInfoManage;component/Images/Navigation/ArchiveInfo.png" Width="60"/> 
  32.                         <TextBlock x:Name="Tb_ArchiveManage" Text="{Binding Tb_ArchiveManage,0"> 
  33.                         <Image Source="/MISInfoManage;component/Images/Navigation/SystemManage.png" Width="60"/> 
  34.                         <TextBlock x:Name="Tb_SystemManage" Text="{Binding Tb_SystemManage,Source={StaticResource Resource}}" Style="{StaticResource MainPageTextStyle}"/> 
  35.                     </StackPanel> 
  36.                 </Border> 
  37.             </StackPanel> 
  38.         </ScrollViewer> 
  39.         <Button x:Name="BtnLoginInfo" BorderBrush="AliceBlue" Grid.Row="1" Height="30" BorderThickness="1" Background="AliceBlue" FontSize="16"></Button> 
  40.     </Grid> 
  41. </UserControl> 

后台cs代码如下

 
 
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Net;  
  5. using System.Windows;  
  6. using System.Windows.Controls;  
  7. using System.Windows.Documents;  
  8. using System.Windows.Input;  
  9. using System.Windows.Media;  
  10. using System.Windows.Media.Animation;  
  11. using System.Windows.Navigation;  
  12. using System.Windows.Shapes;  
  13. using MISInfoManage.Resources;  
  14.  
  15. namespace MISInfoManage  
  16. {  
  17.     public partial class MainPage : UserControl  
  18.     {  
  19.         public MainPage()  
  20.         {  
  21.             InitializeComponent();  
  22.         }  
  23.  
  24.         public MainPage(string userName):this()  
  25.         {  
  26.             this.BtnLoginInfo.Content = string.Format(MainPageResource.Btn_LoginInfo,userName);  
  27.         }  
  28.  
  29.         private void Border_MouseMove(object sender, MouseEventArgs e)  
  30.         {  
  31.             Border border = sender as Border;  
  32.             border.Background = new SolidColorBrush(Colors.White);  
  33.             border.Background.Opacity = 0.5;  
  34.             border.BorderThickness = new Thickness(1);  
  35.         }  
  36.  
  37.         private void Border_MouseLeave(object sender, MouseEventArgs e)  
  38.         {  
  39.             Border border = sender as Border;  
  40.             border.Background = new SolidColorBrush();  
  41.             border.BorderThickness = new Thickness(0);  
  42.         }  
  43.     }  

好了,本节到此结束,下一节重点进入增删改查,数据验证,双向,单向绑定。

相关文章

如何在Silverlight4(XAML)中绑定IsEnabled属性?我试过简单的...
我正在编写我的第一个vb.net应用程序(但我也会在这里标记c#,...
ProcessFile()是在UIThread上运行还是在单独的线程上运行.如...
我从同行那里听说,对sharepoint的了解对职业生涯有益.我们不...
我正在尝试保存一个类我的类对象的集合.我收到一个错误说明:...
我需要根据Silverlight中的某些配置值设置给定控件的Style.我...