Silverlight MVVM 贴近实战(一)

Silverlight MVVM 贴近实战(一),第1张

概述我没有大牛的本事,只有一颗帮助别人的心,我喜欢写博客。 今天我们通过一个登录得例子来看看Silverlight的用法以及MVVM模式。这系列的博客我会把以前做的一个WinForm的小程序改装成SL。首先先上一张图。 好了功能就这么点,今天我们先把登陆界面做出来。要说这个小程序,我先把程序架构贴出来,如下所示。 首先,SilverLight的宿主是MVC3项目,整个框架采用SilverLight调用

我没有大牛的本事,只有一颗帮助别人的心,我喜欢写博客。

今天我们通过一个登录得例子来看看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(thisnew 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 贴近实战(一)所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1068104.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-26
下一篇 2022-05-26

发表评论

登录后才能评论

评论列表(0条)

保存