Silverlight MVVM 贴近实战(五)

我不像有些大牛能出书做MVP,有些大牛能卖组件开公司,我只是个小程序员。

今天主要是展示Silverlight的验证和OOB(Out Of Browser)模式,对了,我平时最恨那些写博客只写简写而不注明全称的人,所以这里OOB就是Out Of Browser。顾名思义,浏览器外,也就是Silverlight运行在浏览器外。OK,废话不多说,先上一张图,档案信息的修改界面。

点击修改按钮,弹出档案信息修改界面。我们首先看看修改界面的UI代码。

  
  
  
  
  1. <controls:ChildWindow x:Class="MISInfoManage.ArchiveInfoModify" 
  2.            xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"   
  3.            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"   
  4.            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"   
  5.            xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls" 
  6.            Width="480" Height="260" 
  7.            xmlns:LocalResource="clr-namespace:MISInfoManage.Resources"> 
  8.     <controls:ChildWindow.Resources> 
  9.         <LocalResource:ArchiveInfoModifyResource x:Key="LocalResource"/> 
  10.         <Style x:Key="TitleColumnStyle" TargetType="TextBlock"> 
  11.             <Setter Property="FontSize" Value="12"/> 
  12.             <Setter Property="HorizontalAlignment" Value="Right"/> 
  13.         </Style> 
  14.     </controls:ChildWindow.Resources> 
  15.     <Grid x:Name="LayoutRoot" Margin="5"> 
  16.         <Grid.RowDefinitions> 
  17.             <RowDefinition Height="Auto"/> 
  18.             <RowDefinition Height="Auto"/> 
  19.             <RowDefinition Height="Auto"/> 
  20.             <RowDefinition Height="Auto"/> 
  21.             <RowDefinition Height="Auto"/> 
  22.             <RowDefinition Height="Auto"/> 
  23.             <RowDefinition Height="Auto"/> 
  24.         </Grid.RowDefinitions> 
  25.         <Grid.ColumnDefinitions> 
  26.             <ColumnDefinition Width="Auto"/> 
  27.             <ColumnDefinition Width="Auto"/> 
  28.             <ColumnDefinition Width="Auto"/> 
  29.             <ColumnDefinition Width="Auto"/> 
  30.         </Grid.ColumnDefinitions> 
  31.         <TextBlock Text="{Binding Tb_ArchiveNo,Source={StaticResource LocalResource}}" Style="{StaticResource TitleColumnStyle}" Grid.Row="0" Grid.Column="0"/> 
  32.         <TextBox Text="{Binding ArchiveNo,Mode=TwoWay}" Grid.Row="0" Grid.Column="1" FontSize="12" Width="150"/> 
  33.         <TextBlock Text="{Binding Tb_Name,Source={StaticResource LocalResource}}" Style="{StaticResource TitleColumnStyle}" Grid.Row="0" Grid.Column="2" Margin="20,0,0,0"/> 
  34.         <TextBox Text="{Binding Name,Mode=TwoWay,NotifyOnValidationError=True,ValidatesOnExceptions=True,UpdateSourceTrigger=Explicit}" Grid.Row="0" Grid.Column="3" FontSize="12" Width="170"/> 
  35.         <TextBlock Text="{Binding Tb_IdCardNo,Source={StaticResource LocalResource}}" Style="{StaticResource TitleColumnStyle}" Grid.Row="1" Grid.Column="0" Margin="0,5,0,0"/> 
  36.         <TextBox Text="{Binding IdCardNo,Mode=TwoWay,NotifyOnValidationError=True, ValidatesOnExceptions=True}" Grid.Row="1" Grid.Column="1" Margin="0,5,0,0" FontSize="12"/> 
  37.         <TextBlock Text="{Binding Tb_Sex,Source={StaticResource LocalResource}}" Style="{StaticResource TitleColumnStyle}" Grid.Row="1" Grid.Column="2" Margin="20,5,0,0"/> 
  38.         <ComboBox Grid.Row="1" Grid.Column="3" SelectedValuePath="Tag" SelectedValue="{Binding Sex,Mode=TwoWay}" Margin="0,5,0,0" FontSize="12"> 
  39.             <ComboBoxItem Content="男" Tag="1"></ComboBoxItem> 
  40.             <ComboBoxItem Content="女" Tag="0"></ComboBoxItem> 
  41.         </ComboBox> 
  42.         <TextBlock Text="{Binding Tb_Birth,Source={StaticResource LocalResource}}" Style="{StaticResource TitleColumnStyle}" Margin="0,5,0,0" Grid.Row="2" Grid.Column="0"/> 
  43.         <sdk:DatePicker Grid.Row="2" Grid.Column="1" SelectedDate="{Binding BirthDay,Mode=TwoWay,NotifyOnValidationError=True,ValidatesOnExceptions=True}" Margin="0,5,0,0" FontSize="12"/> 
  44.         <TextBlock Text="{Binding Tb_TelNo,Source={StaticResource LocalResource}}" Style="{StaticResource TitleColumnStyle}" Margin="20,5,0,0" Grid.Row="2" Grid.Column="2"/> 
  45.         <TextBox Text="{Binding TelNumber,Mode=TwoWay}" Grid.Row="2" Grid.Column="3" Margin="0,5,0,0" FontSize="12"/> 
  46.         <TextBlock Text="{Binding Tb_Professional,Source={StaticResource LocalResource}}" Style="{StaticResource TitleColumnStyle}" Margin="0,5,0,0" Grid.Row="3" Grid.Column="0"/> 
  47.         <TextBox Text="{Binding Professional,Mode=TwoWay}" Grid.Row="3" Grid.Column="1" Margin="0,5,0,0" FontSize="12"/> 
  48.         <TextBlock Text="{Binding Tb_Education,Source={StaticResource LocalResource}}" Style="{StaticResource TitleColumnStyle}" Margin="20,5,0,0" Grid.Row="3" Grid.Column="2"/> 
  49.         <ComboBox ItemsSource="{Binding EducationList,Mode=OneWay}" DisplayMemberPath="display_content" SelectedValuePath="data" SelectedValue="{Binding Education,Mode=TwoWay}" FontSize="12" Margin="0,5,0,0" Grid.Row="3" Grid.Column="3"/> 
  50.         <TextBlock Text="{Binding Tb_GraduateSchool,Source={StaticResource LocalResource}}" Style="{StaticResource TitleColumnStyle}" Margin="0,5,0,0" Grid.Row="4" Grid.Column="0"/> 
  51.         <TextBox Text="{Binding GraduateSchool,Mode=TwoWay}" Grid.Row="4" Grid.Column="1" Margin="0,5,0,0" FontSize="12"/> 
  52.         <TextBlock Text="{Binding Tb_GraduateYear,Source={StaticResource LocalResource}}" Style="{StaticResource TitleColumnStyle}" Margin="20,5,0,0" Grid.Row="4" Grid.Column="2"/> 
  53.         <TextBox Text="{Binding GraduateYear,Mode=TwoWay,NotifyOnValidationError=True,ValidatesOnExceptions=True}" Grid.Row="4" Grid.Column="3" Margin="0,5,0,0" FontSize="12"/> 
  54.         <TextBlock Text="{Binding Tb_ArchiveState,Source={StaticResource LocalResource}}" Style="{StaticResource TitleColumnStyle}" Margin="0,5,0,0" Grid.Row="5" Grid.Column="0"/> 
  55.         <ComboBox Grid.Row="5" Grid.Column="1" SelectedValuePath="Tag" SelectedValue="{Binding ArchiveState,Mode=TwoWay}" Margin="0,5,0,0" FontSize="12"> 
  56.             <ComboBoxItem Content="已提" Tag="0"/> 
  57.             <ComboBoxItem Content="在库" Tag="1"/> 
  58.         </ComboBox> 
  59.         <StackPanel Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="4" Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,10,0,0"> 
  60.             <Button Content="{Binding Btn_Modify,Source={StaticResource LocalResource}}" Width="80" Height="25" Margin="0,0,10,0" Click="Button_Click" Tag="m"/> 
  61.             <Button Content="{Binding Btn_Cancel,Source={StaticResource LocalResource}}" Width="80" Height="25" Click="Button_Click" Tag="c"/> 
  62.         </StackPanel> 
  63.     </Grid> 
  64. </controls:ChildWindow> 

大家看到了,也是Grid和StackPanel布局。我们看到里面有这样一段代码

  
  
  
  
  1. <ComboBox Grid.Row="1" Grid.Column="3" SelectedValuePath="Tag" SelectedValue="{Binding Sex,Mode=TwoWay}" Margin="0,5,0,0" FontSize="12"> 
  2.             <ComboBoxItem Content="男" Tag="1"></ComboBoxItem> 
  3.             <ComboBoxItem Content="女" Tag="0"></ComboBoxItem> 
  4.         </ComboBox> 

注意,这里SelectedValuePath="Tag",这里指定了这个下拉列表的SelectedValue值绑定的是自己的ComboBoxItem Tag属性。如果选择了男,下拉列表的SelectedValue值就是1,如果选择女,则SelectedValue值是0。也就是这里绑定的SelectedValue="{Binding Sex,Mode=TwoWay}" ,即ViewModel的Sex属性。

再往下看有这么一段代码

  
  
  
  
  1. <TextBox Text="{Binding Name,Mode=TwoWay,NotifyOnValidationError=True,ValidatesOnExceptions=True}" Grid.Row="0" Grid.Column="3" FontSize="12" Width="170"/> 

在这里绑定的是ViewModel的Name属性,NotifyOnValidationError和ValidatesOnExceptions用来捕获验证出现的异常。我们来看看ViewModel的代码

  
  
  
  
  1. namespace ViewModel  
  2. {  
  3.     public class ArchiveInfoModifyModel  
  4.     {  
  5.         public string ArchiveNo { getset; }  
  6.  
  7.         private string archiveState;  
  8.         public string ArchiveState   
  9.         {  
  10.             get { return archiveState; }  
  11.             set   
  12.             {  
  13.                 archiveState = value;  
  14.                 NotifyPropertyChange("ArchiveState");  
  15.             }  
  16.         }  
  17.  
  18.         private string sex;  
  19.         public string Sex   
  20.         {  
  21.             get { return sex; }  
  22.             set 
  23.             {  
  24.                 sex = value;  
  25.                 NotifyPropertyChange("Sex");  
  26.             }  
  27.         }  
  28.  
  29.         private string education { getset; }  
  30.         public string Education   
  31.         {  
  32.             get { return education; }  
  33.             set 
  34.             {  
  35.                 education = value;  
  36.                 NotifyPropertyChange("Education");  
  37.             }  
  38.         }  
  39.  
  40.         private DateTime? birthDay;  
  41.         public DateTime? BirthDay   
  42.         {  
  43.             get { return birthDay; }  
  44.             set 
  45.             {  
  46.                 birthDay = value;  
  47.                 if (value > DateTime.Now.AddYears(-15) || value < DateTime.Now.AddYears(-50))  
  48.                 {  
  49.                     throw new ValidationException("出生日期不正确!");  
  50.                 }  
  51.                 NotifyPropertyChange("BirthDay");  
  52.             }  
  53.         }  
  54.  
  55.         private string professional;  
  56.         public string Professional   
  57.         {  
  58.             get { return professional; }  
  59.             set 
  60.             {  
  61.                 professional = value;  
  62.                 NotifyPropertyChange("Professional");  
  63.             }  
  64.         }  
  65.  
  66.         private int? graduateYear;  
  67.         [Range(1950,2012,ErrorMessage="毕业年份不正确!")]  
  68.         public int? GraduateYear   
  69.         {  
  70.             get { return graduateYear; }  
  71.             set 
  72.             {  
  73.                 var validatorContext = new ValidationContext(thisnullnull);  
  74.                 validatorContext.MemberName = "GraduateYear";   
  75.                 Validator.ValidateProperty(value, validatorContext);  
  76.                 graduateYear = value;  
  77.                 NotifyPropertyChange("GraduateYear");  
  78.             }  
  79.         }  
  80.  
  81.         private string name;  
  82.         [Required(ErrorMessage="姓名不能为空!")]  
  83.         [StringLength(8,ErrorMessage="姓名长度不能超过8!")]  
  84.         public string Name   
  85.         {  
  86.             get { return name; }  
  87.             set 
  88.             {  
  89.                 var validatorContext = new ValidationContext(thisnullnull);  
  90.                 validatorContext.MemberName = "Name";  
  91.                 Validator.ValidateProperty(value, validatorContext);  
  92.                 name = value;  
  93.                 NotifyPropertyChange("Name");  
  94.             }  
  95.         }  
  96.  
  97.         private string idCardNo;  
  98.         public string IdCardNo   
  99.         {  
  100.             get { return idCardNo; }  
  101.             set 
  102.             {  
  103.                 idCardNo = value;  
  104.                 NotifyPropertyChange("IdCardNo");  
  105.             }  
  106.         }  
  107.  
  108.         private string graduateSchool;  
  109.         public string GraduateSchool  
  110.         {  
  111.             get { return graduateSchool; }  
  112.             set 
  113.             {  
  114.                 graduateSchool = value;  
  115.                 NotifyPropertyChange("GraduateSchool");  
  116.             }  
  117.         }  
  118.  
  119.         private string telNumber;  
  120.         public string TelNumber  
  121.         {  
  122.             get 
  123.             {  
  124.                 return telNumber;  
  125.             }  
  126.             set 
  127.             {  
  128.                 telNumber = value;  
  129.                 NotifyPropertyChange("TelNumber");  
  130.             }  
  131.         }  
  132.  
  133.         private ObservableCollection<ViewModel.ArchiveInfoService.Codes> educationList;  
  134.         public ObservableCollection<ViewModel.ArchiveInfoService.Codes> EducationList  
  135.         {  
  136.             get 
  137.             {  
  138.                 return educationList;  
  139.             }  
  140.             set 
  141.             {  
  142.                 educationList = value;  
  143.                 NotifyPropertyChange("EducationList");  
  144.             }  
  145.         }  
  146.  
  147.         public event PropertyChangedEventHandler PropertyChanged;  
  148.         private void NotifyPropertyChange(string property)  
  149.         {  
  150.             if (PropertyChanged != null)  
  151.             {  
  152.                 PropertyChanged(thisnew PropertyChangedEventArgs(property));  
  153.             }  
  154.         }  
  155.     }  

我们看到了Name和GraduateYear等加入了验证。Name验证了非空和长度,采用的是标注Attribute的格式,和MVC的验证方式一样,需要引入System.ComponentModel.DataAnnotations命名空间。其中的Birthday属性采用了抛出异常的方式,当抛出异常后,页面UI会接收到异常信息,并显示红色的提示信息,因为Birthday设置了ValidatesOnExceptions=True。我们来看看验证的效果。

UI会提示出生日期不正确。如果毕业年份输入不正确,也会给出提示信息。

因为毕业年份设置了NotifyOnValidationError=True。所以在这里NotifyOnValidationError对应于设置ValidationAttribute的方式,而ValidatesOnExceptions对应于Set访问器中的抛出异常方式。在这里我特别要注意说明的是

  
  
  
  
  1. <TextBox Text="{Binding Name,Mode=TwoWay,NotifyOnValidationError=True,ValidatesOnExceptions=True,UpdateSourceTrigger=Explicit}" Grid.Row="0" Grid.Column="3" FontSize="12" Width="170"/> 

在这里有一个UpdateSourceTrigger,这个属性有两个值,一个是默认的Default,一个是Explicit,有什么区别呢?我们在用MVVM的时候,经常会碰到这样一种场景,在文本框输入一个值,然后直接按回车键查数据或者别的什么操作,但是你会发现回车后取得的文本框得值仍然是文本框上次的值(没有失去焦点前的值)。为什么呢?这就是这里要说的UpdateSourceTrigger,在双向绑定下,大多数控件默认是在PropertyChanged以后就会更改ViewModel的值,但是TextBox则默认是失去焦点以后才会更改ViewModel的值。所以在这里我也不默认了,直接改成UpdateSourceTrigger=Explicit,显式的调用BindingExpression的UpdateSource方法获取页面上的值,将其反映到ViewModel上。这就意味着,只有在在调用了UpdateSource方法以后才会启用验证。上述讲的验证只是在失去焦点以后的验证,大多数情况下我们是要点击提交按钮以后来验证,并且验证不通过,不能再执行下面的逻辑。这个在我们web开发中很容易实现,但是在Silverlight中怎么实现呢?我们看看后台

  
  
  
  
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Globalization;  
  4. using System.Linq;  
  5. using System.Net;  
  6. using System.Threading;  
  7. using System.Windows;  
  8. using System.Windows.Data;  
  9. using System.Windows.Controls;  
  10. using System.Windows.Documents;  
  11. using System.Windows.Input;  
  12. using System.Windows.Media;  
  13. using System.Windows.Media.Animation;  
  14. using System.Windows.Shapes;  
  15. using Client.Common;  
  16. using ViewModel;  
  17.  
  18. namespace MISInfoManage  
  19. {  
  20.     public partial class ArchiveInfoModify : ChildWindow  
  21.     {  
  22.         string archiveNo;  
  23.         ArchiveInfoModifyModel viewModel;  
  24.         ViewModel.ArchiveInfoService.ArchiveInfoServiceClient client;  
  25.         public ArchiveInfoModify()  
  26.         {  
  27.             InitializeComponent();  
  28.             this.Title = "档案信息修改";  
  29.         }  
  30.  
  31.         public ArchiveInfoModify(string archiveNo)  
  32.             : this()  
  33.         {  
  34.             this.archiveNo = archiveNo;  
  35.             viewModel = new ArchiveInfoModifyModel();  
  36.             this.Loaded += delegate(object sender, RoutedEventArgs e)  
  37.             {  
  38.                 client = new ViewModel.ArchiveInfoService.ArchiveInfoServiceClient();  
  39.                 client.GetEducationCompleted += delegate(object sender1, ViewModel.ArchiveInfoService.GetEducationCompletedEventArgs e1)  
  40.                 {  
  41.                     viewModel.EducationList = new System.Collections.ObjectModel.ObservableCollection<ViewModel.ArchiveInfoService.Codes>(e1.Result);  
  42.                     this.GetArchiveInfoByNo();  
  43.                 };  
  44.                 client.GetEducationAsync();  
  45.             };  
  46.         }  
  47.  
  48.         private void Button_Click(object sender, RoutedEventArgs e)  
  49.         {  
  50.             Button button = sender as Button;  
  51.             if (button.Tag.ToString().Equals("m"))  
  52.             {  
  53.                 if (!this.ValidateData())  
  54.                 {  
  55.                     return;  
  56.                 }  
  57.                 ViewModel.ArchiveInfoService.Person_Info personInfo = new ViewModel.ArchiveInfoService.Person_Info()  
  58.                 {  
  59.                     birth = viewModel.BirthDay.Value,  
  60.                     contact_tel = viewModel.TelNumber,  
  61.                     education_level = viewModel.Education,  
  62.                     graduate_school = viewModel.GraduateSchool,  
  63.                     graduate_year = viewModel.GraduateYear.Value,  
  64.                     id_card = viewModel.IdCardNo,  
  65.                     name = viewModel.Name,  
  66.                     no = viewModel.ArchiveNo,  
  67.                     professional = viewModel.Professional,  
  68.                     sex = viewModel.Sex,  
  69.                     state = viewModel.ArchiveState  
  70.                 };  
  71.                 client.ModifyArchiveInfoCompleted += delegate(object modifySender, ViewModel.ArchiveInfoService.ModifyArchiveInfoCompletedEventArgs modifyArgs)  
  72.                 {  
  73.                     new Thread(() =>  
  74.                     {  
  75.                         UISynchronizationContext.Context.Post((state) =>  
  76.                         {  
  77.                             MessageBox.Show("修改成功!");  
  78.                         }, null);  
  79.                     }).Start();  
  80.                 };  
  81.                 client.ModifyArchiveInfoAsync(personInfo);  
  82.             }  
  83.             if (button.Tag.ToString().Equals("c"))  
  84.             {  
  85.                 this.Close();  
  86.             }  
  87.         }  
  88.  
  89.         private void GetArchiveInfoByNo()  
  90.         {  
  91.             client.GetPersonInfoByIDCompleted += delegate(object sender, ViewModel.ArchiveInfoService.GetPersonInfoByIDCompletedEventArgs e)  
  92.             {  
  93.                 ViewModel.ArchiveInfoService.Person_Info personInfo = e.Result;  
  94.                 this.viewModel.ArchiveNo = personInfo.no;  
  95.                 this.viewModel.ArchiveState = personInfo.state;  
  96.                 this.viewModel.BirthDay = personInfo.birth;  
  97.                 this.viewModel.Education = personInfo.education_level;  
  98.                 this.viewModel.GraduateSchool = personInfo.graduate_school;  
  99.                 this.viewModel.GraduateYear = personInfo.graduate_year;  
  100.                 this.viewModel.IdCardNo = personInfo.id_card;  
  101.                 this.viewModel.Name = personInfo.name;  
  102.                 this.viewModel.Professional = personInfo.professional;  
  103.                 this.viewModel.Sex = personInfo.sex;  
  104.                 this.viewModel.TelNumber = personInfo.contact_tel;  
  105.                 this.LayoutRoot.DataContext = viewModel;  
  106.             };  
  107.             client.GetPersonInfoByIDAsync(archiveNo);  
  108.         }  
  109.  
  110.         private bool ValidateData()  
  111.         {  
  112.             UIElementCollection UIElments = LayoutRoot.Children;  
  113.             foreach (var element in UIElments)  
  114.             {  
  115.                 if (element.GetType() == typeof(TextBox))  
  116.                 {  
  117.                     TextBox textbox = element as TextBox;  
  118.                     BindingExpression expression = textbox.GetBindingExpression(TextBox.TextProperty);  
  119.                     if (expression.ParentBinding.NotifyOnValidationError == true || expression.ParentBinding.ValidatesOnExceptions == true)  
  120.                     {  
  121.                         expression.UpdateSource();  
  122.                         if (Validation.GetHasError(textbox))  
  123.                         {  
  124.                             return false;  
  125.                         }  
  126.                     }  
  127.                 }  
  128.                 if (element.GetType() == typeof(ComboBox))  
  129.                 {  
  130.                     ComboBox comboBox = element as ComboBox;  
  131.                     BindingExpression expression = comboBox.GetBindingExpression(ComboBox.SelectedValueProperty);  
  132.                     if (expression.ParentBinding.NotifyOnValidationError == true || expression.ParentBinding.ValidatesOnExceptions == true)  
  133.                     {  
  134.                         expression.UpdateSource();  
  135.                         if (Validation.GetHasError(comboBox))  
  136.                         {  
  137.                             return false;  
  138.                         }  
  139.                     }  
  140.                 }  
  141.                 if (element.GetType() == typeof(DatePicker))  
  142.                 {  
  143.                     DatePicker datepicker = element as DatePicker;  
  144.                     BindingExpression expression = datepicker.GetBindingExpression(DatePicker.SelectedDateProperty);  
  145.                     if (expression.ParentBinding.NotifyOnValidationError == true || expression.ParentBinding.ValidatesOnExceptions == true)  
  146.                     {  
  147.                         expression.UpdateSource();  
  148.                         if (Validation.GetHasError(datepicker))  
  149.                         {  
  150.                             return false;  
  151.                         }  
  152.                     }  
  153.                 }  
  154.             }  
  155.             return true;  
  156.         }  
  157.     }  
  158. }  

我们看看这个Button_Click事件,在修改方法中,我们调用了ValidateData方法,该方法循环遍历页面UIElment,并强制更新ViewModel中的值。如果发现验证不通过,直接返回False,在Button_Click事件中,如果没有通过验证,就不再执行修改操作。这样就实现了验证不通过,就不再往下走的逻辑。关于验证,我就说到这里,如有不懂,可以加入.net群205217091,我可以把源代码共享给大家。我们看看服务端代码

  
  
  
  
  1. public int ModifyArchiveInfo(Person_Info personInfoModel)  
  2.         {  
  3.             Person_Info personInfo = misInfoEntities.person_info.SingleOrDefault(p => p.no.Equals(personInfoModel.no));  
  4.             Type type = personInfo.GetType();  
  5.             PropertyInfo[] propertyInfos = type.GetProperties().Where(p=>!p.Name.Equals("id")).ToArray();  
  6.             foreach (var propertyInfo in propertyInfos)  
  7.             {  
  8.                 propertyInfo.SetValue(personInfo, propertyInfo.GetValue(personInfoModel, null));  
  9.             }  
  10.             return misInfoEntities.SaveChanges();  
  11.         } 

 这个后台代码也没什么,循环遍历利用反射赋值,最后调用DBContext的SaveChanges方法完成更新。好了,最后我们看看OOB模式。

在Silverlight 项目上点击右键,打开属性设置界面,如下所示

我们勾选Enable running application out of browser,然后点击Out-of-Browser Settings按钮,弹出设置界面,如下

我们设置了高度和宽度,以及window style等信息。OK,我们再次将程序运行起来。我们发现点击右键多了一项“将MISInformation Application 安装到此计算机...”。我们点击安装后,出现下面的界面

勾选开始和桌面后,点击确定,我们发现桌面上多了一个图标,如下所示

我们双击它,弹出如下界面,即我们的OOB运行模式

 OK,看到了吧,Title是我们上面设置的档案信息管理。怎么样,这样的Silverlight运行方式是不是很不错。它同样能够实现在浏览器中的功能,如下

好了,今天就讲这么多,如果大家需要源代码,直接找我要,或者加入.net群205217091。

你可能感兴趣的:(silverlight,MVVM)