silverlight 学习笔记 (四): MVVM+WCF Ria开发架构


在前两已经基本了解了silverlight的基本开发思路,其中在应用MVVM架构有很多不解,经过这两天学习才大致了解了一些。有几个初学者常犯得错误需要提醒

1、silverlight 是一个富客户端应用程序,silverlight应用程序会以xap包方式加载到客户端,既然是客户端应用程序那么就没法直接与后台数据库进行访问,这就需要用到Webservice,WCF,WCF RIA等技术实现客户端与服务器端的数据传输,所以放弃以前在些asp.net时直接写sql调用后台数据库吧!

2、silverlight 不支持DataTable,DataSet等数据集方式的数据传输,我们不得不使用实体数据集方式进行数据传输了,不过国外有牛人做了一个工具将datatable转化成xml传输到客户在再进一步将字符串转化成实体数据集供silverlight使用。有兴趣可以搜索Silverlight.DataSet,使用起来还是很方便的,对我们在一些无法确定实体类的情况下查询有很大帮助。

3、在silverlight 中应用MVVM时,其中Model+ViewModel+View都是silverlight客户端程序,它们直接可以相互引用,但别幻想着应用Web应用程序库,因为Web应用程序库在服务器端使用的

下面开始重点介绍的silverlight 中应用MVVM+WCF RIA的开发架构,由于只学了两天,没有太多时间深入,只能把目前了解到的记录下来

1、MVVM即model(实体)+View(界面)+ViewModel(逻辑),model层负责建立数据实体,保障数据加载,是View中数据绑定的基本元素(但不是说View中去绑定Model实例)。View层不多说,强烈建议使用Microsoft Expression Blend进行界面设计,所有的数据展示及事件都采用绑定形式,这样设计人员就与开发人员彻底分离了,具体实现见上节。ViewModel层是联系View层与Model层的桥梁,View层所有的数据绑定都直接指向ViewModel。这里的model,view,viewmodel都是客户端silverlight应用,可以建立多个silverlight应用库项目已进行系统结构上的分割。

2、silverlight的数据传输:以本人目前所了解的多数情况下都是采用WCF RIA方式,其优点google上了解吧。我之所以选择WCF RIA 是因为它比WCF 实现起来简单多了,而且由于RIA Link的存在,让我们客户端使用服务器端应用逻辑如同客户端一样,这样就解决了silverlight客户端与服务器端无法共享业务逻辑了,同时RIA Link 会在客户端生成服务器端的“影子代码”,让开发人员不再担心客户端与服务器端代码同步的问题了。

3、WCF RIA的设计:目前大多数网上查的资料都是在使用ado.net数据实体+Domain service方式,而我所了解的是ado.net 数据实体模型只支持MS SqlServer ,而对于oracle还需要再去下载一个odac for 11g 才行,痛苦啊!同时如果我们要从原有系统的wcf 服务提供数据 ,那就意味着要在Domain Service 中定义自己的CURD了。我索性直接采用自定义实体类+自定义Domain service方法了。

下面重点讲下步骤:

1、在解决方案中选择建立web应用程序库(service),注意如果该web应用程序与Silverlight的host不在一个项目则Silverlight 的host Web项目要引用该Web项目(service),同时修改Web.config,可参照Service项目下的web.config,否则会出现错误:远程服务器返回了错误: NotFound。在Web应用程序库中建立实体类,注意实体类中必须要有主键

 

 public class Items
    {
        [Key]
        public string SItemCode { get; set; }
        public string SItemName { get; set; }

    }


 2、建立Domain Servcie类

[EnableClientAccess()]
    public class DomainService1 : DomainService
    {
        public List<Items> GetItems()
        {
            List<Items> items = new List<Items>();
            for (int i = 1; i < 10; i++)
            {
                Items item = new Items();
                item.SItemCode = "A" + i.ToString();
                item.SItemName = "this is " + i.ToString();
                items.Add(item);
            }
            return items;
        }
        [Update]
        public void UpdateData(Items item)
        { 
           //可添加SQL进行数据库操作
            string s = item.SItemName;
        }
        [Delete]
        public void DeleteData(Items item)
        {
            string s = item.SItemName;
        }
        [Insert]
        public void InsertData(Items item)
        {
            string s = item.SItemName;
        }
    }


在建立类时[EnableClientAccess()]标识将能指示该类将在RIA Link中映射到客户端,本例子中建立了4个公共方法,为了简便我没有加入sql进行数据库的访问,GetItems()是给客户端查询提供数据,UpdateData()用来更新数据,需要注意的是在该方法上指定了[Update]属性,这样客户端在实体数据发生变化后可以应用此方法更新数据库数据,如果没有指定数据更新方法在客户端数据发生变化后会出现错误。删除、和添加方法定义一样。

3、建立silverlight应用程序,在silverlight项目上应用RIA Link,方法是在silverlight项目属性上在WCF RIA服务链接选择我们前面建立的Web应用程序库项目,这样在编译项目项目后会在该silverlight项目中添加一个隐藏的文件夹Generated_Code,这个文件夹中的内容是由系统产生,是根据我们之前定义的Domain Service类建立的,其中包含了一个DomainContext类和Entity实体类,我们可以应用该文件夹下所有的类。

4、建立ViewModel,为了简单我暂不建立Model类,在ViewModel中可以使用Ria Link 产生的DomainContext类中的包含实体集合类

 public EntitySet<Items> Items
        {
            get
            {
                return base.EntityContainer.GetEntitySet<Items>();
            }
        }

同时在该DomainContext会建立一个根据DomainService1 类中建立的数据查询方法

 public EntityQuery<Items> GetItemsQuery()
        {
            this.ValidateMethod("GetItemsQuery", null);
            return base.CreateQuery<Items>("GetItems", null, false, true);
        }


在ViewModel中定义属性及事件

 public class ItemViewModel:INotifyPropertyChanged
    {
        DomainService1 server = new DomainService1();
        private Items _seletedItem = new Items();
        public Items SeletedItem
        {
            get { return _seletedItem; }

            set
            {
                if (value != _seletedItem)
                {
                    _seletedItem = value;
                    
                    PropertyChanged(this, new PropertyChangedEventArgs("SeletedItem"));
                }
            }
        }

        //private EntityQuery<Items> _itemList = new EntityQuery<Items>();
        public EntitySet<Items> ItemList
        {
            get { return server.Items; }
           
        }

        public ICommand OnLoad { get { return new DelegateCommand(LoadData); } }
        private void LoadData(object obj)
        {
            
            EntityQuery<Items> list =   server.GetItemsQuery();
            LoadOperation<Items> loadOp = server.Load(list);
           // loadOp.Completed += new EventHandler(loadOp_Completed);
           
        }

        void loadOp_Completed(object sender, EventArgs e)
        {
            foreach (Items item in server.Items)
            {
                Items u = new Items();
                u.SItemCode = item.SItemCode;
                u.SItemName = item.SItemName;
                //ItemList.Add(u);
            }
        }

        public ICommand OnUpdate { get { return new DelegateCommand(UpdateData); } }
        private void UpdateData(object obj)
        {
           
           
            server.SubmitChanges();
        }
        public ICommand OnDelete { get { return new DelegateCommand(DeleteData); } }

        private void DeleteData(object obj)
        {
            server.Items.Remove(this.SeletedItem);
            server.SubmitChanges();
        }

        public ICommand OnInsert { get { return new DelegateCommand(InsertData); } }
        public void InsertData(object obj) {
            Items item = new Items();
            item.SItemCode = Guid.NewGuid().ToString();
            item.SItemName = obj.ToString();
            server.Items.Add(item);
            server.SubmitChanges();
        }
        public ICommand OnSelectChanged { get { return new DelegateCommand(SelectionChanged); } }

        private void SelectionChanged(object obj)
        {
            if (obj != null)
            {
                SeletedItem = obj as Items;

            }
            else
            {
                SeletedItem = null;

            }
        }
        #region INotifyPropertyChanged 成员

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

   
    }


通过server.SubmitChanges();可以将数据的变化反馈到服务器端的DomainService类中,DomainService类会根据数据集中的数据状态调用相应的方法进行数据处理,需要注意的是silverlight是采用异步处理模式,所以我们要考虑在服务器端的domainservice类中进行数据同步验证处理,以后深入讲解。

5、建立View,进行数据绑定

<Grid x:Name="LayoutRoot" Background="White" DataContext="{Binding Source={StaticResource ItemViewModelDataSource}}">
        <sdk:DataGrid AutoGenerateColumns="true" Height="119" HorizontalAlignment="Left" Margin="21,169,0,0" x:Name="dataGrid1" VerticalAlignment="Top" Width="320" ItemsSource="{Binding ItemList, Source={StaticResource ItemViewModelDataSource}}" DataContext="{Binding}" SelectedItem="{Binding SeletedItem, Mode=TwoWay}" >
        	<i:Interaction.Triggers>
        		<i:EventTrigger EventName="SelectionChanged">
        			<i:InvokeCommandAction Command="{Binding OnSelectChanged, Mode=OneWay}" CommandParameter="{Binding SeletedItem}"/>
        		</i:EventTrigger>
        	</i:Interaction.Triggers>
        </sdk:DataGrid>
        <Button Content="查询" Height="23" HorizontalAlignment="Left" Margin="35,55,0,0" x:Name="button1" VerticalAlignment="Top" Width="75" Command="{Binding OnLoad, Mode=OneWay}" />
        <Button Content="更新" Height="23" HorizontalAlignment="Left" Margin="116,55,0,0" x:Name="button2" VerticalAlignment="Top" Width="75" Command="{Binding OnUpdate, Mode=OneWay}" />
        <Button Content="删除" Height="23" HorizontalAlignment="Left" Margin="197,55,0,0" x:Name="button3" VerticalAlignment="Top" Width="75" Command="{Binding OnDelete, Mode=OneWay}" CommandParameter="{Binding SelectedItem, ElementName=dataGrid1}" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="46,106,0,0" x:Name="textBox1" VerticalAlignment="Top" Width="120" />
        <Button Content="添加" Height="23" HorizontalAlignment="Left" Margin="172,106,0,0" x:Name="button4" VerticalAlignment="Top" Width="75" Command="{Binding OnInsert, Mode=OneWay}" CommandParameter="{Binding Text, ElementName=textBox1}" />
    </Grid>


整个过程演示了MVVM+WCF RIA架构的实现,其中还有很多内部细节尚未深入,不过整体架构已见雏形!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值