我没有大牛的本事,只有一颗帮助别人的心,我喜欢写博客。
今天我们通过一个登录得例子来看看Silverlight的用法以及MVVM模式。这系列的博客我会把以前做的一个WinForm的小程序改装成SL。首先先上一张图。
好了功能就这么点,今天我们先把登陆界面做出来。要说这个小程序,我先把程序架构贴出来,如下所示。
首先,Silverlight的宿主是MVC3项目,整个框架采用Silverlight调用Controller/Action的模式。在Server端我们用到了领域驱动设计一小部分,为了降低耦合,采用了Unity注入。在Server端,主要包括Repository泛型设计,EntityFrameWork 4.1 edmx,Domain中的一个小工厂模式,以及应用层,业务层。他们之间的调用关系依次为Application调用Repository,Business调用Application,Controller调用Business,而Model贯穿于它们。具体的大家看看代码就知道了。在ClIEnt端,主要包括Common,DataAccess,Entity,viewmodel,Common主要是一些加密解密,序列化、反序列化等。DataAccess主要是负责调用Controller/Action,从Server端获取数据。Entity包括一些反序列化对象,以及向Server端传递的对象(如果调用的是MVC的Controller,都必须序列化成Json或者XML,如果调用的是WCF或者WebService,定义成DTO就可以了)。viewmodel定义了与页面和Model交互的一些对象,一般是用来双向绑定。好了基本上就是这么一个情况。我们看看代码,首先看ClIEnt端的登陆界面。
<navigation:Page x:Class="MISInfoManage.Login" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/Expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:navigation="clr-namespace:System.windows.Controls;assembly=System.windows.Controls.Navigation" xmlns:source="clr-namespace:MISInfoManage.Resources" Title="Login Page" Loaded="Page_Loaded"> <navigation:Page.Resources> <source:LoginResource x:Key="LoginResource"></source:LoginResource> </navigation:Page.Resources> <GrID x:name="LayoutRoot"> <GrID.Background> <ImageBrush ImageSource="/MISInfoManage;component/Images/LoginBack.jpg" /> </GrID.Background> <GrID.RowDeFinitions> <RowDeFinition Height="300"></RowDeFinition> <RowDeFinition Height="auto"></RowDeFinition> <RowDeFinition Height="auto"></RowDeFinition> <RowDeFinition Height="auto"></RowDeFinition> </GrID.RowDeFinitions> <GrID.ColumnDeFinitions> <ColumnDeFinition WIDth="530" ></ColumnDeFinition> <ColumnDeFinition WIDth="*"></ColumnDeFinition> </GrID.ColumnDeFinitions> <TextBlock Text="{Binding Tb_Title,Source={StaticResource LoginResource}}" FontSize="48" FontFamily="Arial" Foreground="White" GrID.Row="0" GrID.Column="0" GrID.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock> <TextBlock FontSize="16" HorizontalAlignment="Right" Text="{Binding Tb_Username, Source={StaticResource LoginResource}}" GrID.Row="1" GrID.Column="0"></TextBlock> <TextBox Text="{Binding UserNo,Mode=TwoWay}" WIDth="300" GrID.Row="1" GrID.Column="1" margin="0,15" HorizontalAlignment="left" Height="30"></TextBox> <TextBlock Text="{Binding Tb_UserPwd,Source={StaticResource LoginResource}}" GrID.Row="2" GrID.Column="0" HorizontalAlignment="Right" FontSize="16"></TextBlock> <TextBox Text="{Binding UserPwd,Mode=TwoWay}" WIDth="300" GrID.Row="2" GrID.Column="1" HorizontalAlignment="left" Height="30"></TextBox> <StackPanel GrID.Row="3" GrID.Column="0" GrID.ColumnSpan="2" HorizontalAlignment="Center" OrIEntation="Horizontal"> <button x:name="BtnLogin" Content="{Binding BtnLogin,Source={StaticResource LoginResource}}" margin="80,20,0" Style="{StaticResource BtnLoginStyle}" Click="BtnLogin_Click"></button> <button x:name="BtnCancel" Content="{Binding BtnCancel,Source={StaticResource LoginResource}}" margin="10,0" WIDth="90" Style="{StaticResource BtnLoginStyle}" Click="BtnCancel_Click"></button> </StackPanel> </GrID> </navigation:Page>
在这里需要说明的是几个Binding,其中
<TextBlock Text="{Binding Tb_Title,Source={StaticResource LoginResource}}" FontSize="48" FontFamily="Arial" Foreground="White" GrID.Row="0" GrID.Column="0" GrID.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
这段代码绑定的是一段文字“人事档案管理系统”。在哪里呢,在我们定义的资源文件里。
就是LoginResource.resx文件,我们打开看看
看到了吧,在这里需要注意的是每次更改为资源文件后,必须把访问修饰符改成Public,并且把资源文件对应的cs文件中的构造函数的修饰符改成public。这个资源文件在页面我们需要引用一下。就是页面顶端这段代码:xmlns:source="clr-namespace:MISInfoManage.Resources",以及<navigation:Page.Resources>
<source:LoginResource x:Key="LoginResource"></source:LoginResource>
</navigation:Page.Resources>这两段。OK页面看完了,我们看看后台。
using System; using System.Collections.Generic; using System.linq; using System.Net; using System.windows; using System.windows.Controls; using System.windows.documents; using System.windows.input; using System.windows.Media; using System.windows.Media.Animation; using System.windows.Shapes; using System.windows.Navigation; using System.IO; namespace MISInfoManage { using viewmodel; using DataAccess.Login; using ClIEnt.Common; using ClIEnt.Entity; using MISInfoManage.Resources; public partial class Login : Page { LoginUser user; public Login() { InitializeComponent(); } private voID Page_Loaded(object sender, RoutedEventArgs e) { user = new LoginUser(); this.LayoutRoot.DataContext = user; } private voID BtnLogin_Click(object sender, RoutedEventArgs e) { if (string.IsNullOrWhiteSpace(user.UserNo)) { CommonMessage.ShowInfo(MessageResource.Login_Msg_UserNoIsEmpty); return; } if (string.IsNullOrWhiteSpace(user.userPwd)) { CommonMessage.ShowInfo(MessageResource.Login_Msg_UserPwdisEmpty); return; } LoginDAL.Instance.GetUser(user.UserNo, (obj, args) => { if (args.Error == null) { Stream stream = args.Result; User loginUser = SerIEalizeHelper<User>.JsonDeserialize<User>(stream); if (loginUser != null) { string passWordEncrypt = loginUser.user_password; Cryptor cryptor = new Cryptor(); string passWord = cryptor.Decrypt(passWordEncrypt.tochararray()); if (!(passWord.Tolower() == user.UserPwd.Tolower())) { CommonMessage.ShowInfo(MessageResource.Login_Msg_UserNotCorrect); return; } else { this.Content = new MainPage(loginUser.user_name); } } else { CommonMessage.ShowInfo(MessageResource.Login_Msg_UserNotCorrect); return; } } else { CommonMessage.ShowInfo(args.Error.Message); } }); } private voID BtnCancel_Click(object sender, RoutedEventArgs e) { this.user.UserPwd = string.Empty; this.user.UserNo = string.Empty; } } }
需要注意的是Page_Load的时候, this.LayoutRoot.DataContext = user;这就将一个viewmodel绑定到了页面,我们注意到页面上的用户名和密码都是采用双向绑定,Mode=TwoWay,如果Mode=TwoWay,那么只要文本框值更改了,对应的viewmodel的值也会改变,如果viewmodel值变了,文本框也会体现出来变化。但是viewmodel中的属性都需要进行跟踪。
public class LoginUser : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public string userNo; public string UserNo { get { return userNo; } set { userNo = value; NotifyPropertyChange("UserNo"); } } public string userPwd; public string UserPwd { get { return userPwd; } set { userPwd = value; NotifyPropertyChange("UserPwd"); } } private voID NotifyPropertyChange(string property) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(property)); } } }
这就是为什么我在点击按钮取消的时候,没有直接 *** 作文本框,而是 this.user.UserPwd = string.Empty;this.user.UserNo = string.Empty;因为双向绑定。我们重点看GetUser这个方法,LoginDAL.Instance.GetUser(user.UserNo,(obj,args) => {})这里第二个参数我是用来回调的一个匿名委托。我们看看LoginDAL中的这个方法。
public class LoginDAL : BaseDAL { public static Readonly LoginDAL Instance = new LoginDAL(); private LoginDAL() { } public voID GetUser(string userNo, OpenReadCompletedEventHandler handler) { WebClIEnt webClIEnt = new System.Net.WebClIEnt(); Uri uri = this.GetUri("Login/GetUser/" + userNo); webClIEnt.OpenReadAsync(uri); webClIEnt.OpenReadCompleted += handler; } }
第二个参数是一个委托:public delegate voID OpenReadCompletedEventHandler(object sender,OpenReadCompletedEventArgs e);相信大家这下理解了吧。我们往下看,
Stream stream = args.Result;
User loginUser = SerIEalizeHelper<User>.JsonDeserialize<User>(stream);
这段是从Server端取到Stream以后,进行反序列化,反序列化成客户端对象,然后我们根据反序列化生成的对象进行相关判断。在本例子中我需要说明的是,本来按钮的事件不应该出现在页面代码中,而是要在viewmodel中做处理,在页面按钮上绑定Command,但是介于这只是个登陆界面,所以.......。另外关于Server端的详细情况由于篇幅有限就不说了。我们看看运行效果
登陆以后进入主页面,这个主页面我现在还没做好,但是登陆成功的跳转是绝对没问题的,不忽悠大家。主页面导航我准备采用类似于苹果桌面或者windows 7界面。好了今天就到这里,下期继续。
总结以上是内存溢出为你收集整理的Silverlight MVVM 贴近实战(一)全部内容,希望文章能够帮你解决Silverlight MVVM 贴近实战(一)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)