zoukankan      html  css  js  c++  java
  • WPF——初识MVVM(二)

    说明:该案例与前一个案例的来源一样,同样讲述的是MVVM,算是MVVM的进阶吧。在该案例中,涉及到数据访问,Prism等更为复杂的问题。首先来看界面设计,我在作者的基础上稍微做了改动,大致如下:

    1.首先还是来一个解决方案的截图:

    2.实现步骤

    2.1)从OO的角度来说,首先是完成基类的书写,该案例主要有两个对象,是Dish类(菜品类)和Restaurant(餐馆类),实现起来都较为简单,具体如下:

    Restaurant Class
     1  public class Restaurant
     2     {
     3         /// <summary>
     4         /// 餐馆名称
     5         /// </summary>
     6         public string Name
     7         {
     8             get;
     9             set;
    10         }
    11 
    12         /// <summary>
    13         /// 餐馆地址
    14         /// </summary>
    15         public string Address
    16         {
    17             get;
    18             set;
    19         }
    20 
    21         /// <summary>
    22         /// 订餐电话
    23         /// </summary>
    24         public string PhoneNumber
    25         {
    26             get;
    27             set;
    28         }
    29     }
    Dish Class Code
     1 /// <summary>
     2     ///菜品类
     3     /// </summary>
     4     class Dish
     5     {
     6         //1.Data Property
     7         /// <summary>
     8         /// 菜品名称
     9         /// </summary>
    10         public string Name { get; set; }
    11         /// <summary>
    12         /// 菜品类别
    13         /// </summary>
    14         public string Category { get; set; }
    15         /// <summary>
    16         /// 菜品评论
    17         /// </summary>
    18         public string Comment { get; set; }
    19         /// <summary>
    20         /// 菜品评分
    21         /// </summary>
    22         public double Score { get; set; }
    23     }



    2.2)接口的定义和实现

    无论是从技术上还是从团队的角度来谈,使用接口的好处是显而易见的。这里做个简单的架设,该项目中的数据源是xml,如果涉及到不同的数据源就可以用不同的方法来实现接口来获取数据。

    首先定义接口IDataService和IOrderService:

    1 interface IDataService
    2     {
    3        List<Dish> GetAllDishes();
    4     }
    IOrderService
    1  interface IOrderService
    2     {
    3         void PlaceOrder(List<string> dishes);
    4     }


    接口的实现:

    XmlDataService
     1  class XmlDataService :IDataService
     2     {
     3         public List<Dish> GetAllDishes()
     4         {
     5             List<Dish> dishList = new List<Dish>();
     6             //System.IO.Path.Combine将两个字符串组合成一个路径(http://msdn.microsoft.com/zh-cn/library/z8te35sa(v=vs.80).aspx)
     7             string xmlFileName = System.IO.Path.Combine(Environment.CurrentDirectory, @"Data\Data.xml");
     8             //XDocument.Load(string uri)
     9             XDocument xDoc = XDocument.Load(xmlFileName);
    10             //按文档顺序返回此文档或元素的经过筛选的子代元素集合。集合中只包括具有匹配 XName 的元素。
    11             //XName即Data.xml中的 <Dish></Dish>节点
    12             var dishes = xDoc.Descendants("Dish");
    13             //IEnumerable dishes = xDoc.Descendants("Dish");
    14 
    15             foreach (var d in dishes)
    16             {
    17                 Dish dish = new Dish();
    18                 dish.Name = d.Element("Name").Value;
    19                 dish.Category = d.Element("Category").Value;
    20                 dish.Comment = d.Element("Comment").Value;
    21                 dish.Score = double.Parse(d.Element("Score").Value);
    22                 dishList.Add(dish);
    23             }
    24             return dishList;
    25         }
    26         
    27     }
    MockOrderService
    1  class MockOrderService :IOrderService
    2     {
    3         public void PlaceOrder(List<string> dishes)
    4         {
    5             System.IO.File.WriteAllLines(@"C:\order.txt", dishes.ToArray());
    6         }
    7     }

    说明:该XmlDataService的作用是从xml文件中读取数据,MockOrderService则是简单的将订单信息存储在本地磁盘。

    2.3)主要的业务逻辑实现

    这里涉及到了Prism,Prism已经为我们实现了INotifyPropertyChangedICommand接口,我们只需添加引用集,添加命名空间和使相关类继承NotificationObject。

     1  using Microsoft.Practices.Prism.ViewModel;
     2  using MVVMDemo2.Models;
     3 
     4 class DishMenuItemViewModel : NotificationObject
     5     {
     6         public Dish Dish { get; set; }//(有一个关系)
     7 
     8         private bool isSelected;
     9 
    10         public bool IsSelected
    11         {
    12             get { return isSelected; }
    13             set
    14             {
    15                 isSelected = value;
    16                 this.RaisePropertyChanged("IsSelected");
    17             }
    18         }
    19 
    20     }

     

    在引用了Microsoft.Practices.Prism.ViewModel命名空间,并继承NotificationObject后就可以使用RasisePropertyChanged()方法了,NotificationObject实际上派生自INotifyPropertyChanged。

     

      1 using Microsoft.Practices.Prism.ViewModel;
      2 using Microsoft.Practices.Prism.Commands;
      3 using MVVMDemo2.Services;
      4 using System.Windows;
      5 
      6 namespace MVVMDemo2.ViewModels
      7 {
      8     class MainWindowViewModel : NotificationObject
      9     {
     10         #region 定义命令属性和数据属性
     11         //Command property
     12         public DelegateCommand PlaceOrderCommand { get; set; }
     13         public DelegateCommand SelectMenuItemCommand { get; set; }
     14 
     15         //Data Property
     16         /// <summary>
     17         /// 选择个数
     18         /// </summary>
     19         private int count;
     20 
     21         public int Count
     22         {
     23             get { return count; }
     24             set
     25             {
     26                 count = value;
     27                 //若不继承NotificationObject,这里将会报错
     28                 this.RaisePropertyChanged("Count");
     29             }
     30         }
     31 
     32         /// <summary>
     33         /// 餐馆信息
     34         /// </summary>
     35         private Restaurant restaurant;
     36 
     37         public Restaurant Restaurant
     38         {
     39             get { return restaurant; }
     40             set
     41             {
     42                 restaurant = value;
     43                 this.RaisePropertyChanged("Restaurant");
     44             }
     45         }
     46 
     47         /// <summary>
     48         /// 餐馆菜品
     49         /// </summary>
     50         private List<DishMenuItemViewModel> dishMenu;
     51 
     52         public List<DishMenuItemViewModel> DishMenu
     53         {
     54             get { return dishMenu; }
     55             set
     56             {
     57                 dishMenu = value;
     58                 this.RaisePropertyChanged("DishMenu");
     59             }
     60         }
     61         #endregion
     62 
     63 
     64         public MainWindowViewModel()
     65         {
     66             this.LoadRestaurant();
     67             this.LoadDishMenu();
     68 
     69             this.PlaceOrderCommand = new DelegateCommand(new Action(this.PlaceOrderCommandExecute));
     70             this.SelectMenuItemCommand = new DelegateCommand(new Action(this.SelectMenuItemExecute));
     71 
     72         }
     73 
     74         /// <summary>
     75         /// 加载餐馆信息
     76         /// </summary>
     77         private void LoadRestaurant()
     78         {
     79             this.Restaurant = new Restaurant();
     80 
     81             this.Restaurant.Name = "乔治伊诺";
     82             this.Restaurant.Address = "小花园立交桥西口233号";
     83             this.Restaurant.PhoneNumber = "0932313520";
     84 
     85         }
     86 
     87         /// <summary>
     88         /// 加载菜品信息
     89         /// </summary>
     90         private void LoadDishMenu()
     91         {
     92             IDataService ds = new XmlDataService();
     93             var dishes = ds.GetAllDishes();
     94             this.DishMenu = new List<DishMenuItemViewModel>();
     95             foreach (var dish in dishes)
     96             {
     97                 DishMenuItemViewModel item = new DishMenuItemViewModel();
     98                 item.Dish = dish;
     99                 this.DishMenu.Add(item );
    100                    
    101             }
    102 
    103         }
    104 
    105         /// <summary>
    106         /// 执行订餐操作
    107         /// </summary>
    108         private void PlaceOrderCommandExecute()
    109         {
    110             var selectedDishes = this.DishMenu.Where(i => i.IsSelected == true).Select(i => i.Dish.Name).ToList();
    111            
    112             IOrderService orderService = new MockOrderService();
    113             orderService.PlaceOrder(selectedDishes);
    114             //var unSelected = this.DishMenu.Where(i => i.IsSelected == false).Select(i => i.Dish.Name).ToList();
    115             // orderService.PlaceOrder(unSelected);
    116             MessageBox.Show("订餐成功!");
    117         }
    118 
    119         /// <summary>
    120         /// 执行操作
    121         /// </summary>
    122         private void SelectMenuItemExecute()
    123         {
    124             this.Count = this.DishMenu.Count(i=>i.IsSelected==true);
    125         }
    126 
    127     }
    128 }

    说明:添加了 Microsoft.Practices.Prism.Commands命名空间,就可以使用DelegateCommand,如上代码所示。其继承层次结构为:DelegateCommand>DelegateCommandBae>ICommand, IActiveAware。

     

    最后通过在CS中添加 this.DataContext = new MainWindowViewModel();并在XAML代码中进行绑定即可:

    View XAML
     1 <Window x:Class="MVVMDemo2.MainWindow"
     2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     4         Title="{Binding Restaruant.Name,StringFormat=\{0\}-在线订餐}"  Height="600" Width="1000" WindowStartupLocation="CenterScreen">
     5     <Border BorderThickness="10" Name="borderWrap" Background="Orange" BorderBrush="GreenYellow" CornerRadius="10">
     6         <Border BorderBrush="Orange" BorderThickness="3" CornerRadius="6" Background="Yellow">
     7             <Grid x:Name="Root" Margin="4">
     8                 <Grid.RowDefinitions>
     9                     <RowDefinition Height="Auto" />
    10                     <RowDefinition Height="*" />
    11                     <RowDefinition Height="Auto" />
    12                 </Grid.RowDefinitions>
    13                 <Border BorderBrush="Orange" BorderThickness="2" CornerRadius="6" Padding="4">
    14                     <StackPanel>
    15                         <StackPanel Orientation="Horizontal">
    16                             <StackPanel.Effect>
    17                                 <DropShadowEffect Color="LightGray" />
    18                             </StackPanel.Effect>
    19                             <TextBlock Text="欢迎光临-" FontSize="60" FontFamily="KaiTi" />
    20                             <TextBlock Text="{Binding Restaurant.Name}" FontSize="60" FontFamily="LiShu" />
    21                         </StackPanel>
    22                         <StackPanel Orientation="Horizontal">
    23                             <TextBlock Text="餐厅地址:" FontSize="24" FontFamily="LiShu" />
    24                             <TextBlock Text="{Binding Restaurant.Address}" FontSize="24" FontFamily="LiShu" />
    25                         </StackPanel>
    26                         <StackPanel Orientation="Horizontal">
    27                             <TextBlock Text="订餐电话:" FontSize="24" FontFamily="LiShu" />
    28                             <TextBlock Text="{Binding Restaurant.PhoneNumber}" FontSize="24" FontFamily="LiShu" />
    29                         </StackPanel>
    30                     </StackPanel>
    31                 </Border>
    32                 <DataGrid AutoGenerateColumns="False" GridLinesVisibility="None" CanUserDeleteRows="False"
    33                     CanUserAddRows="False" Margin="0,4" Grid.Row="1" FontSize="16" ItemsSource="{Binding DishMenu}">
    34                     <DataGrid.Columns>
    35                         <DataGridTextColumn Header="菜品" Binding="{Binding Dish.Name}" Width="120" />
    36                         <DataGridTextColumn Header="种类" Binding="{Binding Dish.Category}" Width="120" />
    37                         <DataGridTextColumn Header="点评" Binding="{Binding Dish.Comment}" Width="120" />
    38                         <DataGridTextColumn Header="推荐分数" Binding="{Binding Dish.Score}" Width="120" />
    39                         <DataGridTemplateColumn Header="选中" SortMemberPath="IsSelected" Width="120">
    40                             <DataGridTemplateColumn.CellTemplate>
    41                                 <DataTemplate>
    42                                     <CheckBox IsChecked="{Binding Path=IsSelected,  UpdateSourceTrigger=PropertyChanged}"
    43                                         VerticalAlignment="Center" HorizontalAlignment="Center"
    44                                         Command="{Binding Path=DataContext.SelectMenuItemCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGrid}}}" />
    45                                 </DataTemplate>
    46                             </DataGridTemplateColumn.CellTemplate>
    47                         </DataGridTemplateColumn>
    48                     </DataGrid.Columns>
    49                 </DataGrid>
    50                 <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row="2">
    51                     <TextBlock Text="共计" VerticalAlignment="Center" />
    52                     <TextBox IsReadOnly="True" TextAlignment="Center" Width="120" Text="{Binding Count}" Margin="4,0" />
    53                     <Button Content="我要订餐" Height="24" Width="120" Command="{Binding PlaceOrderCommand}" />
    54                 </StackPanel>
    55             </Grid>
    56         </Border>
    57     </Border>
    58 </Window>


    Form:深入浅出WPF MVVM入门与提高(刘铁锰 wpfgeek@live.com)

  • 相关阅读:
    C# 遍历enum类型元素、获取最大值、最小值
    ABAP-成本报表案例
    recovering corrupted postgres database
    自定义QHeaderView后,点击表头排序失效的解决办法
    Visual Studio 2017社区版登录时始终卡在登录界面的另一个登录办法
    已经安装好的TortoiseSVN在更改盘符后不能使用无法卸载也无法安装的解决办法
    使用别人已经静态编译好的Qt库在进行自己的Qt Creator配置时,在配置Qt Version时出现的2个问题解决办法
    ASCII、Unicode和UTF-8,一文看懂,保存链接
    centos7 挂载硬盘操作
    一次性kill所有进程的命令
  • 原文地址:https://www.cnblogs.com/January/p/2440239.html
Copyright © 2011-2022 走看看