使用Prism实现的WPF MVVM点餐Demo

说明:本文出处:http://www.cnblogs.com/DebugLZQ/archive/2012/12/17/2821772.html

·界面上方TextBlock显示餐馆的信息(粉红色字),该信息保存在一个ViewModel的一个餐馆的属性中。

·DataGrid显示菜品信息,从一个模拟的Service中读出;并在最后添加一个CheckBox Binding一个命令用来选择菜品

·下面的TextBox显示选中了几个菜,Button则Binding一个Command实现点菜(象征性的存入本地磁盘)

下面来实现它:

//---------------------

最终的项目的文件结构如下:

前面说过,可以直接饮用Prism,只引入相关的程序集也可以(虽然是一回事),这次我们就这么干!

1.新建一个WpfPrism的WPF项目,添加Prism dll引用,(使用NotificationObject、DelegateCommand)如下:

2.在项目中添加一个Data文件夹,放入Data.XML文件,文件如下:

View Code
  1 View Code 
  2 
  3 <?xml version="1.0" encoding="utf-8"?>
  4 <Dishes>
  5     <Dish>
  6         <Name>土豆泥底披萨</Name>
  7         <Category>披萨</Category>
  8         <Comment>本店特色</Comment>
  9         <Score>4.5</Score>
 10     </Dish>
 11     <Dish>
 12         <Name>烤囊底披萨</Name>
 13         <Category>披萨</Category>
 14         <Comment>本店特色</Comment>
 15         <Score>5</Score>
 16     </Dish>
 17     <Dish>
 18         <Name>水果披萨</Name>
 19         <Category>披萨</Category>
 20         <Comment></Comment>
 21         <Score>4</Score>
 22     </Dish>
 23     <Dish>
 24         <Name>牛肉披萨</Name>
 25         <Category>披萨</Category>
 26         <Comment></Comment>
 27         <Score>5</Score>
 28     </Dish>
 29     <Dish>
 30         <Name>培根披萨</Name>
 31         <Category>披萨</Category>
 32         <Comment></Comment>
 33         <Score>4.5</Score>
 34     </Dish>
 35     <Dish>
 36         <Name>什锦披萨</Name>
 37         <Category>披萨</Category>
 38         <Comment></Comment>
 39         <Score>4.5</Score>
 40     </Dish>
 41     <Dish>
 42         <Name>金枪鱼披萨</Name>
 43         <Category>披萨</Category>
 44         <Comment></Comment>
 45         <Score>5</Score>
 46     </Dish>
 47     <Dish>
 48         <Name>海鲜披萨</Name>
 49         <Category>披萨</Category>
 50         <Comment></Comment>
 51         <Score>5</Score>
 52     </Dish>
 53     <Dish>
 54         <Name>川香披萨</Name>
 55         <Category>披萨</Category>
 56         <Comment></Comment>
 57         <Score>4.5</Score>
 58     </Dish>
 59     <Dish>
 60         <Name>黑椒鸡腿扒</Name>
 61         <Category>特色主食</Category>
 62         <Comment>本店特色</Comment>
 63         <Score>5</Score>
 64     </Dish>
 65     <Dish>
 66         <Name>肉酱意面</Name>
 67         <Category>特色主食</Category>
 68         <Comment>本店特色</Comment>
 69         <Score>5</Score>
 70     </Dish>
 71     <Dish>
 72         <Name>寂寞小章鱼</Name>
 73         <Category>风味小吃</Category>
 74         <Comment></Comment>
 75         <Score>5</Score>
 76     </Dish>
 77     <Dish>
 78         <Name>照烧鸡软骨</Name>
 79         <Category>风味小吃</Category>
 80         <Comment></Comment>
 81         <Score>5</Score>
 82     </Dish>
 83     <Dish>
 84         <Name>芝士青贝</Name>
 85         <Category>风味小吃</Category>
 86         <Comment></Comment>
 87         <Score>4.5</Score>
 88     </Dish>
 89     <Dish>
 90         <Name>奥尔良烤翅</Name>
 91         <Category>风味小吃</Category>
 92         <Comment>秒杀KFC</Comment>
 93         <Score>5</Score>
 94     </Dish>
 95     <Dish>
 96         <Name>双酱煎泥肠</Name>
 97         <Category>风味小吃</Category>
 98         <Comment></Comment>
 99         <Score>4</Score>
100     </Dish>
101     <Dish>
102         <Name>香酥鱿鱼圈</Name>
103         <Category>风味小吃</Category>
104         <Comment>本店特色</Comment>
105         <Score>4.5</Score>
106     </Dish>
107     <Dish>
108         <Name>黄金蝴蝶虾</Name>
109         <Category>风味小吃</Category>
110         <Comment>本店特色</Comment>
111         <Score>5</Score>
112     </Dish>
113     <Dish>
114         <Name>金枪鱼沙拉</Name>
115         <Category>沙拉</Category>
116         <Comment>本店特色</Comment>
117         <Score>5</Score>
118     </Dish>
119     <Dish>
120         <Name>日式素沙拉</Name>
121         <Category>沙拉</Category>
122         <Comment></Comment>
123         <Score>5</Score>
124     </Dish>
125     <Dish>
126         <Name>冰糖洛神</Name>
127         <Category>饮料</Category>
128         <Comment></Comment>
129         <Score>5</Score>
130     </Dish>
131     <Dish>
132         <Name>玫瑰特饮</Name>
133         <Category>饮料</Category>
134         <Comment></Comment>
135         <Score>5</Score>
136     </Dish>
137     <Dish>
138         <Name>清新芦荟</Name>
139         <Category>饮料</Category>
140         <Comment></Comment>
141         <Score>5</Score>
142     </Dish>
143     <Dish>
144         <Name>薄荷汽水</Name>
145         <Category>饮料</Category>
146         <Comment>本店特色</Comment>
147         <Score>5</Score>
148     </Dish>
149 </Dishes>

3.在项目中添加Model文件夹。添加两个Model Dish和Restaurant,分别如下:

View Code
 1 View Code 
 2 
 3 namespace WpfPrism.Models
 4 {
 5     class Dish
 6     {
 7         public string Name { get; set; }
 8 
 9         public string Category { get; set; }
10 
11         public string  Comment { get; set; }
12 
13         public string  Score { get; set; }
14     }
15 }
View Code
 1 View Code 
 2 
 3 namespace WpfPrism.Models
 4 {
 5     class Restaurant
 6     {
 7         public string Name { get; set; }
 8 
 9         public string Address { get; set; }
10 
11         public string  PhoneNumber { get; set; }
12     }
13 }
View Code
 1 View Code 
 2 
 3 namespace WpfPrism.Models
 4 {
 5     class Restaurant
 6     {
 7         public string Name { get; set; }
 8 
 9         public string Address { get; set; }
10 
11         public string  PhoneNumber { get; set; }
12     }
13 }

4.在项目中添加Services文件夹,其中IDataService、XMLDataService用来定义和实现:获取菜品信息功能。IOrderService和MockOrderService用来定义和实现:点菜功能。之所以使用接口,是为了定义和实现相分离!
其代码依次如下:

View Code
 1 View Code 
 2 
 3 using System.Collections.Generic;
 4 using WpfPrism.Models;
 5 
 6 namespace WpfPrism.Services
 7 {
 8     interface IDataService
 9     {
10         List<Dish> GetAllDishes();
11     }
12 }
View Code
 1 View Code 
 2 
 3 using System;
 4 using System.Collections.Generic;
 5 using WpfPrism.Models;
 6 using System.IO;
 7 using System.Xml.Linq;
 8 
 9 
10 namespace WpfPrism.Services
11 {
12     class XMLDataService:IDataService//接口:定义和实现相分离
13     {
14         #region IDataService 成员
15 
16         public List<Models.Dish> GetAllDishes()
17         {
18             List<Dish> dishList = new List<Dish>();
19 
20             string xmlFile = Path.Combine(Environment.CurrentDirectory, @"Data/Data.xml");
21 
22             XDocument xDoc = XDocument.Load(xmlFile);
23             var dishes = xDoc.Descendants("Dish");
24             foreach (var d in dishes)
25             {
26                 Dish dish = new Dish();
27                 dish.Name = d.Element("Name").Value;
28                 dish.Category = d.Element("Category").Value;
29                 dish.Comment = d.Element("Comment").Value;
30                 dish.Score = d.Element("Score").Value;
31                 dishList.Add(dish);
32             }
33 
34             return dishList;
35         }
36 
37         #endregion
38     }
39 }
View Code
 1 View Code 
 2 
 3 using System.Collections.Generic;
 4 
 5 namespace WpfPrism.Services
 6 {
 7     interface IOrderService
 8     {
 9         void PlaceOrder(List<string> dishes);
10     }
11 }
View Code
 1 View Code 
 2 
 3 using System.Collections.Generic;
 4 using System.IO;
 5 
 6 namespace WpfPrism.Services
 7 {
 8     class MockOrderService:IOrderService//接口:实现定义和实现相分离
 9     {
10         #region IOrderService 成员
11 
12         public void PlaceOrder(List<string> dishes)
13         {
14             File.WriteAllLines(@"D:/order.txt", dishes.ToArray());
15         }
16 
17         #endregion
18     }
19 }

5.在项目中添加一个ViewModels文件夹,并添加两个Model:DishMenuItemViewModel和MianWindowViewModel。

稍微解释一下:MianWindowViewModel中的一个属性是List<MianWindowViewModel>类型的。两者代码分别如下:

View Code
 1 using Microsoft.Practices.Prism.ViewModel;
 2 using WpfPrism.Models;
 3 
 4 namespace WpfPrism.ViewModels
 5 {
 6     class DishMenuItemViewModel:NotificationObject
 7     {
 8         public Dish Dish { get; set; }
 9 
10         private bool isSelected;
11         public bool IsSelected//这个地方刚开始写错了,废了太大的劲才找出来(注意拼写!)
12         {
13             get { return isSelected; }
14             set 
15             {
16                 isSelected = value;
17                 RaisePropertyChanged("IsSelected");
18             }
19         }
20     }
21 }
View Code
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using Microsoft.Practices.Prism.ViewModel;
 5 using WpfPrism.Models;
 6 using WpfPrism.Services;
 7 using Microsoft.Practices.Prism.Commands;
 8 using System.Windows;
 9 
10 namespace WpfPrism.ViewModels
11 {
12     class MianWindowViewModel:NotificationObject
13     {
14         private Restaurant restaurant;
15         public Restaurant Restaurant
16         {
17             get { return restaurant; }
18             set
19             {
20                 restaurant = value;
21                 RaisePropertyChanged("Restaurant");
22             }
23         }
24 
25         //外加的一个属性,点菜的数量
26         private int count;
27         public int Count
28         {
29             get { return count; }
30             set
31             {
32                 count = value;
33                 RaisePropertyChanged("Count");
34             }
35         }
36 
37         private List<DishMenuItemViewModel> dishMenu;
38         public List<DishMenuItemViewModel> DishMenu
39         {
40             get { return dishMenu; }
41             set
42             {
43                 dishMenu = value;
44                 RaisePropertyChanged("DishMenu");
45             }
46         }
47 
48         public MianWindowViewModel()
49         {
50             LoadRestuarant();//赋值Restaurant属性
51             LoadDishMenu();//赋值DishMenu属性
52 
53             //初始化两个命令属性
54             PlaceOrderCommand = new DelegateCommand(new Action(PlaceOrderCommandExecute));
55             SelectMenuItemCommand = new DelegateCommand(new Action(SelectMenuItemCommandExecute));
56         }
57 
58         private void LoadRestuarant()
59         {
60             Restaurant = new Restaurant() {Name="百年苏韵", Address="江苏大学", PhoneNumber="0511-12345678"};           
61         }
62 
63         private void LoadDishMenu()
64         {
65             DishMenu = new List<DishMenuItemViewModel>();
66 
67             IDataService ds = new XMLDataService();
68             var dishes = ds.GetAllDishes();
69             foreach (var d in dishes)
70             {
71                 DishMenuItemViewModel item = new DishMenuItemViewModel() {  Dish=d};
72                 DishMenu.Add(item);
73             }
74         }
75 
76         //两个命令属性
77         public DelegateCommand PlaceOrderCommand { get; set; }
78         public DelegateCommand SelectMenuItemCommand { get; set; }
79 
80         private void PlaceOrderCommandExecute()
81         {
82             //获取点菜单
83             var selectedDishes = dishMenu.Where(d => d.IsSelected == true).Select(d => d.Dish.Name).ToList();
84 
85             //仅保存到本地磁盘--可以写一些有意义的代码
86             IOrderService orderService = new MockOrderService();
87             orderService.PlaceOrder(selectedDishes );
88 
89             MessageBox.Show("订餐成功!");
90         }
91 
92         private void SelectMenuItemCommandExecute()
93         {
94             Count = DishMenu.Count(n=>n.IsSelected==true);
95         }
96         
97     }
98 }

注意NotificationObject是ViewModel的基类。

最后,为View添加Binding:

View Code
 1 <Window x:Class="WpfPrism.MainWindow"
 2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4         Title="MainWindow" Height="350" Width="590">
 5     <Grid>
 6         <Grid.RowDefinitions>
 7             <RowDefinition Height="Auto"/>
 8             <RowDefinition Height="*"/>
 9             <RowDefinition Height="Auto"/>
10         </Grid.RowDefinitions>
11         <!-- 餐馆信息-->
12         <StackPanel Grid.Row="0">
13             <StackPanel Orientation="Horizontal" >
14                 <TextBlock Text="欢迎光临-" FontSize="40"/>
15                 <TextBlock Text="{Binding Restaurant.Name}" FontSize="40"  Foreground="HotPink" />
16             </StackPanel>
17             <StackPanel Orientation="Horizontal" >
18                 <TextBlock Text="地址:" FontSize="40"/>
19                 <TextBlock Text="{Binding Restaurant.Address}" FontSize="40" Foreground="HotPink" />
20             </StackPanel>
21             <StackPanel Orientation="Horizontal" >
22                 <TextBlock Text="电话:" FontSize="40"/>
23                 <TextBlock Text="{Binding Restaurant.PhoneNumber}" FontSize="40" Foreground="HotPink" />
24             </StackPanel>
25         </StackPanel>
26         <!--菜品信息,选菜-->
27         <DataGrid Grid.Row="1" ItemsSource="{Binding DishMenu}" AutoGenerateColumns="False" GridLinesVisibility="All" CanUserDeleteRows="False" CanUserAddRows="False" >
28             <DataGrid.Columns>
29                 <!-- 这4个来自(ViewModel )Dish属性,UI上一次读出,不会变-->
30                 <DataGridTextColumn Header="菜名"  Binding="{Binding Dish.Name}" Width="120"/>
31                 <DataGridTextColumn Header="种类"  Binding="{Binding Dish.Category}" Width="120"/>
32                 <DataGridTextColumn Header="点评"  Binding="{Binding Dish.Comment}" Width="120"/>
33                 <DataGridTextColumn Header="推荐指数"  Binding="{Binding Dish.Score}" Width="120"/>
34                 <!--注意这个属性-->
35                 <DataGridTemplateColumn Header="选中" SortMemberPath="IsSelected" Width="120">
36                     <DataGridTemplateColumn.CellTemplate>
37                         <DataTemplate >
38                             <CheckBox IsChecked="{Binding Path=IsSelected,UpdateSourceTrigger=PropertyChanged}"
39                                       VerticalAlignment="Center" HorizontalAlignment="Center" 
40                                       Command="{Binding Path=DataContext.SelectMenuItemCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGrid}}}"/>
41                         </DataTemplate>
42                     </DataGridTemplateColumn.CellTemplate>
43                 </DataGridTemplateColumn>
44             </DataGrid.Columns>
45         </DataGrid>
46         <!--所点菜品个数,点菜-->
47         <StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right" >
48             <TextBlock Text="点了几个菜?" TextAlignment="Center"  />
49             <TextBox IsReadOnly="True" Text="{Binding Count}" Width="120" TextAlignment="Center" />
50             <Button Content="点菜" Command="{Binding PlaceOrderCommand}"/>
51         </StackPanel>
52     </Grid>
53 </Window>
View Code
 1 using System.Windows;
 2 using WpfPrism.ViewModels;
 3 
 4 namespace WpfPrism
 5 {
 6     /// <summary>

 7     /// MainWindow.xaml 的交互逻辑
 8     /// </summary>
 9     public partial class MainWindow : Window
10     {
11         public MainWindow()
12         {
13             InitializeComponent();
14 
15             this.DataContext = new MianWindowViewModel();
16         }
17     }
18 }

可以在D盘找到如下的txt文件:

心得:学习Prism MVVM唯一的方法就是多看优秀的代码、多写代码、多多思考,才能理解其模式原理!

原文地址:https://www.cnblogs.com/zxbzl/p/2950050.html