Silverlight MVVM + WCF Ria Service 餐馆点菜DEMO

本文介绍了如何使用Silverlight MVVM模式结合WCF RIA Services构建一个餐馆点菜的DEMO。首先创建Silverlight Application,并在Web项目中添加Entity Data Model。接着,通过DomainService实现数据访问。UI界面使用DataGrid展示菜品,ViewModel中利用ObservableCollection确保删除操作能实时更新界面。在删除数据时,需从原始数据源查找并移除,而非创建新对象。源代码可在优快云下载。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1) 新建Silverlight Application,然后再.Web项目中添加相应数据库的Entity Data Model 数据模型。

2) 在.Web项目中添加中间层DomainService,来用于在Silverlight Application中访问Entity Data Model数据库。

3) 设计UI界面MainPage.xaml:


<UserControl xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"  x:Class="SLCrazyElephant.Client.MainPage"
    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:viewModel="clr-namespace:SLCrazyElephant.Client.ViewModels"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <UserControl.Resources>
        <viewModel:MainWindowViewModel x:Key="viewModel"/>
    </UserControl.Resources>
        <StackPanel x:Name="stackPanel">
        <TextBlock Text="{Binding Restaurant.Name}" Margin="5"/>
        <TextBlock Text="{Binding Restaurant.Address}" Margin="5"/>
        <TextBlock Text="{Binding Restaurant.Phone}" Margin="5"/>
        <sdk:DataGrid AutoGenerateColumns="False" IsReadOnly="True" ItemsSource="{Binding DishItem,Mode=TwoWay}" x:Name="dataGrid">
            <sdk:DataGrid.Columns>
                <sdk:DataGridTextColumn Header="菜品" Binding="{Binding Dish.Name}"/>
                <sdk:DataGridTextColumn Header="种类" Binding="{Binding Dish.Category}"/>
                <sdk:DataGridTextColumn Header="点评" Binding="{Binding Dish.Comment}"/>
                <sdk:DataGridTextColumn Header="推荐分数" Binding="{Binding Dish.Score}"/>
                <sdk:DataGridTemplateColumn Header="选中" Width="120">
                    <sdk:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <CheckBox IsChecked="{Binding IsSelected,Mode=TwoWay}" VerticalAlignment="Center" HorizontalAlignment="Center" Command="{Binding SelectMenuItemCommand,Source={StaticResource viewModel}}"/>                            
                        </DataTemplate>
                    </sdk:DataGridTemplateColumn.CellTemplate>
                </sdk:DataGridTemplateColumn>
                <!--<sdk:DataGridTemplateColumn Header="功能" Width="Auto">
                    <sdk:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button Content="删除" Margin="10" Command="{Binding DeleteCommand,Source={StaticResource viewModel}}" Height="24"/>
                        </DataTemplate>
                    </sdk:DataGridTemplateColumn.CellTemplate>
                </sdk:DataGridTemplateColumn>-->
            </sdk:DataGrid.Columns>
        </sdk:DataGrid>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
            <TextBlock Text="合计" VerticalAlignment="Center"/>
            <TextBox IsReadOnly="True" TextAlignment="Center" Width="120" Text="{Binding Count,Mode=TwoWay}" Margin="5"/>
            <Button Content="Order" Height="24" Width="120" Command="{Binding OrderCommand}"/>
            <Button Content="Delete" Height="24" Width="120" Command="{Binding DeleteCommand}"/>
        </StackPanel>
    </StackPanel>
</UserControl>

注意 这里的 CheckBox的Command使用了Source={StaticResource viewModel} 是因为在DataGrid里的CheckBox无法触发该Command命令,需要在xaml里实例化一个。ViewModel后,在触发该ViewModel里的Comand方法,这也导致了合计Count不好使(暂时还不知道如何解决)。

4) 该View对应的ViewModel:

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Practices.Prism.ViewModel;
using SLCrazyElephant.Web;
using System.Collections.Generic;
using Microsoft.Practices.Prism.Commands;
using System.Linq;
using System.ServiceModel.DomainServices.Client;
using System.Collections.ObjectModel;

namespace SLCrazyElephant.Client.ViewModels
{
    public class MainWindowViewModel:NotificationObject
    {
        //DomainService客户端代理类
        private RestaurantDomainContext _RestaurantDomainContext = new RestaurantDomainContext();

        //数据属性
        private Restaurant restaurant;
        public Restaurant Restaurant
        {
            get { return restaurant; }
            set
            {
                this.restaurant = value;
                this.RaisePropertyChanged("Restaurant");
            }
        }

        //一定要用ObservableCollection泛型类型的 否则无法在删除完DishItem后直接在UI上刷新最新的DishItem
        private ObservableCollection<DishMenuItemViewModel> dishItem;
        public ObservableCollection<DishMenuItemViewModel> DishItem
        {
            get { return dishItem; }
            set
            {
                this.dishItem = value;
                this.RaisePropertyChanged("DishItem");
            }
        }

        private int count;
        public int Count
        {
            get { return count; }
            set
            {
                this.count = value;
                this.RaisePropertyChanged("Count");
            }
        }

        //命令属性
        public DelegateCommand OrderCommand { get; set; }
        public DelegateCommand SelectMenuItemCommand { get; set; }
        public DelegateCommand DeleteCommand { get; set; }

        public void DeleteCommandExecute()
        {
            //删除选中的数据 这里删不掉 因为删除的对象必须是原声的Dish对象,新建的对象是无法删除的。
            //Two objects of same type and attributes do not necessarily mean they are same, by same they should be on the same memory location.
            //You need to find the item that matches the same attributes in your datasoure and then delete that.

            var selectedDishes = this.DishItem.Where(i => i.IsSelected == true);
            foreach (var s in selectedDishes)
            {
                //先把选择的Dish菜名的Name传入到方法里,查询出对应数据库中的Dish对象
                var query = this._RestaurantDomainContext.GetSelectedDishQuery(s.Dish.Name);
                this._RestaurantDomainContext.Load(query, (lo) =>
                    {
                        //然后再删除
                        this._RestaurantDomainContext.Dishes.Remove(lo.Entities.First());
                        //由于Load方法是延时处理方法,所以SubmitChange要放到这里来处理,不能放在外面
                        this._RestaurantDomainContext.SubmitChanges();
                        MessageBox.Show(string.Format("{0}删除成功",lo.Entities.First().Name));
                        //为了删除后直接在DataGrid上刷新出最新删除后的状态
                        this.DishItem.Remove(s);
                    }, null
                    );
            }                        
        }

        public void OrderCommandExecute()
        { 
            //存储到数据库里操作
            List<OrderedDish> odList = new List<OrderedDish>();
            try
            {
                var orderedDishes = this.DishItem.Where(i => i.IsSelected == true);
                foreach (var dish in orderedDishes)
                {
                    OrderedDish od = new OrderedDish();
                    od.Score = dish.Dish.Score;
                    od.Category = dish.Dish.Category;
                    od.Comment = dish.Dish.Comment;
                    od.Name = dish.Dish.Name;                    
                    //od.Score = 87;
                    //od.Name = "Name1";
                    //od.Category = "C1";
                    //od.Comment = "Comment1";
                    this._RestaurantDomainContext.OrderedDishes.Add(od);
                }
                //var s = this._RestaurantDomainContext.OrderedDishes;
                this._RestaurantDomainContext.SubmitChanges();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        public void SelectMenuItemCommandExecute()
        { 
            //算出Count的值            
            this.Count = this.DishItem.Where(i => i.IsSelected == true).Count();
        }

        public MainWindowViewModel()
        {
            this.LoadRestaurant();
            this.LoadDishMenu();
            this.OrderCommand = new DelegateCommand(new Action(this.OrderCommandExecute));
            this.SelectMenuItemCommand = new DelegateCommand(new Action(this.SelectMenuItemCommandExecute));
            this.DeleteCommand = new DelegateCommand(new Action(this.DeleteCommandExecute));
        }

        private void LoadDishMenu()
        {
            //加载菜品列表            
            var query = _RestaurantDomainContext.GetDishQuery();
            _RestaurantDomainContext.Load(query, (lo) =>
                {
                    //先从DomainService里取出Dish的所有对象
                    var dishList = lo.Entities.ToList();
                    //创建一个新的List<DishMenuItemViewModel>对象组
                    this.DishItem = new ObservableCollection<DishMenuItemViewModel>();
                    DishItem.Clear();
                    //foreach循环把从数据库取出的Dish赋给Item的Dish属性,这样就可以保证有Dish和IsSelected两个属性
                    foreach (var dish in dishList)
                    {
                        DishMenuItemViewModel item = new DishMenuItemViewModel();
                        item.Dish = dish;
                        this.DishItem.Add(item);
                    }
                }, null
                );
        }

        private void LoadRestaurant()
        {
            //指定query为GetRestaurantQuery()的引用
            var query = _RestaurantDomainContext.GetRestaurantQuery();
            //然后Load该query,并且把Query出来的对象赋给Restaurant属性,这里一定要保证using System.Linq;要不没法直接使用.First()方法
            _RestaurantDomainContext.Load(query, (lo) =>
                {
                    this.Restaurant = lo.Entities.First();                    
                }, null
            );
        }        
    }
}


这里需要注意:

dishItem必须要定义为ObservableCollection类型的属性,否则(例如改为List类型的)无法在删除数据的时候马上刷新DataGrid。

删除数据的时候需要把源edmx里的数据先查询出来后在删除,不要考虑使用new一个新对象的方法来删除,这样是无法找到要删除的对象的,这是由于new出来的对象并不是真正在内存里的原对象,而且要记得在删除成功后使用DishItem.Remove()方法来改变DishItem属性,从而使得UI上的DataGrid也产生刷新操作。



5) 采用了在ViewModel中有一个的方法,新建了一个DishMenu的ViewModel:

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using SLCrazyElephant.Web;
using Microsoft.Practices.Prism.ViewModel;
using Microsoft.Practices.Prism.Commands;

namespace SLCrazyElephant.Client.ViewModels
{
    public class DishMenuItemViewModel:NotificationObject
    {
        private Dish dish;
        public Dish Dish
        {
            get { return this.dish; }
            set
            {
                this.dish = value;
                this.RaisePropertyChanged("Dish");
            }
        }

        private bool isSelected;
        public bool IsSelected
        {
            get { return isSelected; }
            set
            {
                this.isSelected = value;
                this.RaisePropertyChanged("IsSelected");
                //MessageBox.Show("IsSelected");
            }
        }
    }
}

数据库可使用在项目中的DB.sql脚本生成。

源代码:  http://download.youkuaiyun.com/detail/eric_k1m/6746223

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值