WPF开发学生信息管理系统【WPF+Prism+MAH+WebApi】(完)

  • WPF开发学生信息管理系统【WPF+Prism+MAH+WebApi】(完)已关闭评论
  • 27 次浏览
  • A+
所属分类:.NET技术
摘要

最近通过WPF开发项目,为了对WPF知识点进行总结,所以利用业余时间,开发一个学生信息管理系统【Student Information Management System】。前四篇文章进行了框架搭建和模块划分,后台WebApi接口编写,以及课程管理模块,班级管理模块,学生管理模块的开发,本文在前四篇基础之上,继续深入开发学生信息管理系统的成绩管理和系统管理模块,通过本篇文章,将继续巩固之前的知识点,本文仅供学习分享使用,如有不足之处,还请指正。

最近通过WPF开发项目,为了对WPF知识点进行总结,所以利用业余时间,开发一个学生信息管理系统【Student Information Management System】。前四篇文章进行了框架搭建和模块划分,后台WebApi接口编写,以及课程管理模块,班级管理模块,学生管理模块的开发,本文在前四篇基础之上,继续深入开发学生信息管理系统的成绩管理和系统管理模块,通过本篇文章,将继续巩固之前的知识点,本文仅供学习分享使用,如有不足之处,还请指正。

涉及知识点

学生信息管理系统SIMS属于一个小型的完整系统开发,涉及的知识点比较,具体如下所示:

  1. WPF开发中TextBlock,TextBox,DataGrid,Combox,TabControl等控件的基础使用以及数据绑定等操作。
  2. MAH样式的使用,在本示例中MAH主要用于统一页面风格,提高用户体验。
  3. HttpClient使用,主要用于访问服务端提供的接口。

业务逻辑

前面几篇文章,由浅入深,逐步介绍了课程管理模块,班级管理模块,学生管理模块,今天继续介绍成绩管理模块,业务逻辑关系如下:

  1. 学生属于某一班级之学生,所以学生中包含班级信息。
  2. 班级中存在班长,同时班长又属于学生的一个实体。
  3. 成绩是某一学生的成绩,且一名学生有各门课程的成绩。所以成绩和学生有关,且和课程有关。

实体E-R图

学生表,成绩表,班级表,课程表,各个数据表之间的E-R图,如下所示:

WPF开发学生信息管理系统【WPF+Prism+MAH+WebApi】(完)

由此可见,成绩表与课程和学生表,都有关联,所以放在最后。

成绩管理

成绩管理主要用于录入各个学生各个课程的成绩,包含成绩表的增删改查功能。

1. 成绩管理后台服务Service

IScoreAppService接口是对成绩管理的抽象,如下所示:

 1 namespace SIMS.WebApi.Services.Score  2 {  3     public interface IScoreAppService  4     {  5         public PagedRequest<ScoreEntity> GetScores(string studentName,string courseName,int pageNum,int pageSize);  6   7         /// <summary>  8         /// 通过id查询成绩信息  9         /// </summary> 10         /// <param name="id"></param> 11         /// <returns></returns> 12         public ScoreEntity GetScore(int id); 13  14         /// <summary> 15         /// 新增成绩 16         /// </summary> 17         /// <param name="score"></param> 18         /// <returns></returns> 19         public int AddScore(ScoreEntity score); 20  21         /// <summary> 22         /// 修改成绩 23         /// </summary> 24         /// <param name="score"></param> 25         /// <returns></returns> 26         public int UpdateScore(ScoreEntity score); 27  28         /// <summary> 29         /// 删除成绩 30         /// </summary> 31         /// <param name="id"></param> 32         public int DeleteScore(int id); 33     } 34 }

服务实现类ScoreAppService,是对接口的实现,具体如下所示:

 1 namespace SIMS.WebApi.Services.Score  2 {  3     public class ScoreAppService : IScoreAppService  4     {  5         private DataContext dataContext;  6   7         public ScoreAppService(DataContext dataContext)  8         {  9             this.dataContext = dataContext; 10         } 11  12         public int AddScore(ScoreEntity score) 13         { 14             var entity = this.dataContext.Scores.Add(score); 15             this.dataContext.SaveChanges(); 16             return 0; 17         } 18  19         public int DeleteScore(int id) 20         { 21             var entity = dataContext.Scores.FirstOrDefault(x => x.Id == id); 22             if (entity != null) 23             { 24                 dataContext.Scores.Remove(entity); 25                 dataContext.SaveChanges(); 26             } 27             return 0; 28         } 29  30         public ScoreEntity GetScore(int id) 31         { 32             var entity = dataContext.Scores.FirstOrDefault(r => r.Id == id); 33             return entity; 34         } 35  36         /// <summary> 37         /// 按条件查询成绩列表 38         /// </summary> 39         /// <param name="studentName"></param> 40         /// <param name="courseName"></param> 41         /// <param name="pageNum"></param> 42         /// <param name="pageSize"></param> 43         /// <returns></returns> 44         public PagedRequest<ScoreEntity> GetScores(string studentName, string courseName, int pageNum, int pageSize) 45         { 46             IQueryable<ScoreEntity> scores = null; 47             if (!string.IsNullOrEmpty(studentName) && !string.IsNullOrEmpty(courseName)) 48             { 49                 var students = this.dataContext.Students.Where(r => r.Name.Contains(studentName)); 50                 var courses = this.dataContext.Courses.Where(r => r.Name.Contains(courseName)); 51                 scores = this.dataContext.Scores.Where(r => students.Select(t => t.Id).Contains(r.StudentId)).Where(r => courses.Select(t => t.Id).Contains(r.CourseId)); 52             } 53             else if (!string.IsNullOrEmpty(studentName)) 54             { 55                 var students = this.dataContext.Students.Where(r => r.Name.Contains(studentName)); 56                 scores = this.dataContext.Scores.Where(r => students.Select(t => t.Id).Contains(r.StudentId)); 57             } 58             else if (!string.IsNullOrEmpty(courseName)) 59             { 60                 var courses = this.dataContext.Courses.Where(r => r.Name.Contains(courseName)); 61                 scores = this.dataContext.Scores.Where(r => courses.Select(t => t.Id).Contains(r.CourseId)); 62             } 63             else { 64                 scores = dataContext.Scores.Where(r => true).OrderBy(r => r.Id); 65             } 66             int count = scores.Count(); 67             List<ScoreEntity> items; 68             if (pageSize > 0) 69             { 70                 items = scores.Skip((pageNum - 1) * pageSize).Take(pageSize).ToList(); 71             } 72             else 73             { 74                 items = scores.ToList(); 75             } 76             return new PagedRequest<ScoreEntity>() 77             { 78                 count = count, 79                 items = items 80             }; 81         } 82  83         public int UpdateScore(ScoreEntity score) 84         { 85             dataContext.Scores.Update(score); 86             dataContext.SaveChanges(); 87             return 0; 88         } 89     } 90 }

2. 成绩管理WebApi接口控制器

控制器是对数据服务的公开,每一个控制器的方法表示一个Action,即表示一个客户端可以访问的入口。具体如下所示:

 1 namespace SIMS.WebApi.Controllers  2 {  3     /// <summary>  4     /// 成绩控制器  5     /// </summary>  6     [Route("api/[controller]/[action]")]  7     [ApiController]  8     public class ScoreController : ControllerBase  9     { 10         private readonly ILogger<ScoreController> logger; 11  12         private readonly IScoreAppService scoreAppService; 13  14         public ScoreController(ILogger<ScoreController> logger, IScoreAppService scoreAppService) 15         { 16             this.logger = logger; 17             this.scoreAppService = scoreAppService; 18         } 19  20         /// <summary> 21         /// 获取成绩信息 22         /// </summary> 23         /// <param name="id"></param> 24         /// <returns></returns> 25         [HttpGet] 26         public PagedRequest<ScoreEntity> GetScores(string? studentName, string? courseName, int pageNum, int pageSize) 27         { 28             return scoreAppService.GetScores(studentName, courseName, pageNum, pageSize); 29         } 30  31         /// <summary> 32         /// 获取成绩信息 33         /// </summary> 34         /// <param name="id"></param> 35         /// <returns></returns> 36         [HttpGet] 37         public ScoreEntity GetScore(int id) 38         { 39             return scoreAppService.GetScore(id); 40         } 41  42         /// <summary> 43         /// 新增成绩 44         /// </summary> 45         /// <param name="score"></param> 46         /// <returns></returns> 47         [HttpPost] 48         public int AddScore(ScoreEntity score) 49         { 50             return scoreAppService.AddScore(score); 51         } 52  53         /// <summary> 54         /// 修改成绩 55         /// </summary> 56         /// <param name="score"></param> 57         /// <returns></returns> 58         [HttpPut] 59         public int UpdateScore(ScoreEntity score) 60         { 61             return scoreAppService.UpdateScore(score); 62         } 63  64         /// <summary> 65         /// 删除成绩 66         /// </summary> 67         /// <param name="id"></param> 68         [HttpDelete] 69         public int DeleteScore(int id) 70         { 71             return scoreAppService.DeleteScore(id); 72         } 73     } 74 }

当服务运行起来后,Swagger还每一个控制器都进行归类,可以清晰的看到每一个接口对应的网址,成绩管理模块对应的接口如下所示:

WPF开发学生信息管理系统【WPF+Prism+MAH+WebApi】(完)

 

 

3. 成绩管理客户端接口访问类HttpUtil

在学生信息系统开发的过程中,发现所有的接口访问都是通用的,所以对接口访问功能提取成一个HttpUtil基类【包括GET,POST,PUT,DELETE等功能】,其他具体业务再继承基类,并细化具体业务即可。ScoreHttpUtil代码如下所示:

 1 namespace SIMS.Utils.Http  2 {  3     public class ScoreHttpUtil:HttpUtil  4     {  5         /// <summary>  6         /// 通过id查询成绩信息  7         /// </summary>  8         /// <param name="id"></param>  9         /// <returns></returns> 10         public static ScoreEntity GetScore(int id) 11         { 12             Dictionary<string, object> data = new Dictionary<string, object>(); 13             data["id"] = id; 14             var str = Get(UrlConfig.SCORE_GETSCORE, data); 15             var socre = StrToObject<ScoreEntity>(str); 16             return socre; 17         } 18  19         /// <summary> 20         ///  21         /// </summary> 22         /// <param name="studentName"></param> 23         /// <param name="courseName"></param> 24         /// <param name="pageNum"></param> 25         /// <param name="pageSize"></param> 26         /// <returns></returns> 27         public static PagedRequest<ScoreEntity> GetScores(string? studentName, string? courseName, int pageNum, int pageSize) 28         { 29             Dictionary<string, object> data = new Dictionary<string, object>(); 30             data["courseName"] = courseName; 31             data["studentName"] = studentName; 32             data["pageNum"] = pageNum; 33             data["pageSize"] = pageSize; 34             var str = Get(UrlConfig.SCORE_GETSCORES, data); 35             var socres = StrToObject<PagedRequest<ScoreEntity>>(str); 36             return socres; 37         } 38  39         public static bool AddScore(ScoreEntity socre) 40         { 41             var ret = Post<ScoreEntity>(UrlConfig.SCORE_ADDSCORE, socre); 42             return int.Parse(ret) == 0; 43         } 44  45         public static bool UpdateScore(ScoreEntity socre) 46         { 47             var ret = Put<ScoreEntity>(UrlConfig.SCORE_UPDATESCORE, socre); 48             return int.Parse(ret) == 0; 49         } 50  51         public static bool DeleteScore(int Id) 52         { 53             Dictionary<string, string> data = new Dictionary<string, string>(); 54             data["Id"] = Id.ToString(); 55             var ret = Delete(UrlConfig.SCORE_DELETESCORE, data); 56             return int.Parse(ret) == 0; 57         } 58     } 59 }

4. 成绩管理客户端操作

经过前面四个部分的开发,客户端就可以与数据接口进行交互,展示数据到客户端。客户端所有的开发,均采用MVVM模式进行。

在成绩管理模块中,根据功能区分,主要包含两个View视图及对应的ViewModel。如下所示:

  1. Score视图,主要用于成绩的查询,以及新增,修改,删除的链接入口。
  2. AddEditScore视图,主要用于成绩信息的新增和修改,共用一个视图页面。
  3. 成绩课程不需要页面,所以没有对应视图。

4.1. Score视图

Score视图,主要是成绩的查询和新增,修改,删除的链接入口。涉及知识点如下:

  1. Score视图页面布局采用Grid方式和StackPanel混合布局,即整体布局采用Grid,细微布局采用StackPanel。
  2. 成绩采用分页列表的方式展示,需要用到DataGrid,及分页控件【WPF默认不提供分页控件,可自行编写分页控件】。
  3. 查询条件采用按钮Button和文本框TextBox等组成,关于基础控件的使用,不再详细论述,可参考其他文章。
  4. 在本系统的所有WPF视图中,均需要引入Prism和 MAH组件。
  5. Score视图中,所有的数据均采用Binding的方式与ViewModel进行交互。

Score视图具体代码,如下所示:

  1 <UserControl x:Class="SIMS.ScoreModule.Views.Score"   2              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"   3              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"   4              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"    5              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"    6              xmlns:i="http://schemas.microsoft.com/xaml/behaviors"   7              xmlns:prism="http://prismlibrary.com/"   8              xmlns:local="clr-namespace:SIMS.ScoreModule.Views"   9              mc:Ignorable="d"   10              xmlns:mahApps="http://metro.mahapps.com/winfx/xaml/controls"  11              xmlns:ctrls ="clr-namespace:SIMS.Utils.Controls;assembly=SIMS.Utils"  12              prism:ViewModelLocator.AutoWireViewModel="True"  13              d:DesignHeight="450" d:DesignWidth="800">  14   15     <UserControl.Resources>  16         <ResourceDictionary>  17             <ResourceDictionary.MergedDictionaries>  18                 <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />  19                 <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Blue.xaml" />  20                 <ResourceDictionary>  21                     <Style x:Key="LinkButton" TargetType="Button">  22                         <Setter Property="Background" Value="White"></Setter>  23                         <Setter Property="Cursor" Value="Hand"></Setter>  24                         <Setter Property="Margin" Value="3"></Setter>  25                         <Setter Property="MinWidth" Value="80"></Setter>  26                         <Setter Property="MinHeight" Value="25"></Setter>  27                         <Setter Property="BorderThickness" Value="0 0 0 0"></Setter>  28                     </Style>  29                 </ResourceDictionary>  30             </ResourceDictionary.MergedDictionaries>  31         </ResourceDictionary>  32     </UserControl.Resources>  33     <i:Interaction.Triggers>  34         <i:EventTrigger EventName="Loaded">  35             <i:InvokeCommandAction Command="{Binding LoadedCommand}"></i:InvokeCommandAction>  36         </i:EventTrigger>  37     </i:Interaction.Triggers>  38     <Grid>  39         <Grid.RowDefinitions>  40             <RowDefinition Height="Auto"></RowDefinition>  41             <RowDefinition Height="Auto"></RowDefinition>  42             <RowDefinition Height="*"></RowDefinition>  43             <RowDefinition Height="Auto"></RowDefinition>  44         </Grid.RowDefinitions>  45         <TextBlock Text="成绩信息" FontSize="20" Background="AliceBlue" Margin="2"></TextBlock>  46         <StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Center">  47             <TextBlock Text="学生名称" VerticalAlignment="Center" Margin="2"></TextBlock>  48             <TextBox Margin="4" MinWidth="120" Height="30"  49                      Text="{Binding StudentName}"  50                              HorizontalContentAlignment="Stretch"  51                              mahApps:TextBoxHelper.ClearTextButton="True"  52                              mahApps:TextBoxHelper.Watermark="学生名称"  53                              mahApps:TextBoxHelper.WatermarkAlignment="Left"  54                              SpellCheck.IsEnabled="True" />  55             <TextBlock Text="课程名称" VerticalAlignment="Center" Margin="2"></TextBlock>  56             <TextBox Margin="4" MinWidth="120" Height="30"  57                      Text="{Binding CourseName}"  58                              HorizontalContentAlignment="Stretch"  59                              mahApps:TextBoxHelper.ClearTextButton="True"  60                              mahApps:TextBoxHelper.Watermark="课程名称"  61                              mahApps:TextBoxHelper.WatermarkAlignment="Left"  62                              SpellCheck.IsEnabled="True" />  63             <Button Content="查询" Style="{DynamicResource MahApps.Styles.Button.Square.Accent}" Width="120" Height="30" Margin="3" Command="{Binding QueryCommand}"></Button>  64             <Button Content="新增" Style="{DynamicResource MahApps.Styles.Button.Square.Accent}" Width="120" Height="30" Margin="3" Command="{Binding AddCommand}"></Button>  65         </StackPanel>  66         <DataGrid x:Name="dgScores"  67                   Grid.Row="2"  68                   Grid.Column="0"  69                   Margin="2"  70                   AutoGenerateColumns="False"  71                   CanUserAddRows="False"  72                   CanUserDeleteRows="False"  73                   ItemsSource="{Binding Scores}"  74                   RowHeaderWidth="0">  75             <DataGrid.Columns>  76                 <DataGridTextColumn Binding="{Binding Student.Name}" Header="学生" Width="*" />  77                 <DataGridTextColumn Binding="{Binding Course.Name}" Header="课程" Width="*"/>  78                 <DataGridTextColumn Binding="{Binding Score}" Header="成绩" Width="*"/>  79                 <DataGridTextColumn Binding="{Binding CreateTime, StringFormat=yyyy-MM-dd HH:mm:ss}" Header="创建时间" Width="*"/>  80                 <DataGridTextColumn Binding="{Binding LastEditTime,StringFormat=yyyy-MM-dd HH:mm:ss}" Header="最后修改时间" Width="*"/>  81                 <DataGridTemplateColumn Header="操作" Width="*">  82                     <DataGridTemplateColumn.CellTemplate>  83                         <DataTemplate>  84                             <StackPanel Orientation="Horizontal">  85                                 <Button  Content="Edit" Style="{StaticResource LinkButton}" Command="{Binding RelativeSource={RelativeSource  AncestorType=DataGrid,  Mode=FindAncestor}, Path=DataContext.EditCommand}" CommandParameter="{Binding Id}">  86                                     <Button.Template>  87                                         <ControlTemplate TargetType="Button">  88                                             <TextBlock TextDecorations="Underline" HorizontalAlignment="Center">  89                                                 <ContentPresenter />  90                                             </TextBlock>  91                                         </ControlTemplate>  92                                     </Button.Template>  93                                 </Button>  94                                 <Button Content="Delete" Style="{StaticResource LinkButton}" Command="{Binding RelativeSource={RelativeSource  AncestorType=DataGrid,  Mode=FindAncestor}, Path=DataContext.DeleteCommand}" CommandParameter="{Binding Id}">  95                                     <Button.Template>  96                                         <ControlTemplate TargetType="Button">  97                                             <TextBlock TextDecorations="Underline" HorizontalAlignment="Center">  98                                                 <ContentPresenter />  99                                             </TextBlock> 100                                         </ControlTemplate> 101                                     </Button.Template> 102                                 </Button> 103                             </StackPanel> 104                         </DataTemplate> 105                     </DataGridTemplateColumn.CellTemplate> 106                 </DataGridTemplateColumn> 107             </DataGrid.Columns> 108         </DataGrid> 109         <ctrls:PageControl Grid.Row="3" DataContext="{Binding}" ></ctrls:PageControl> 110     </Grid> 111 </UserControl>

4.2. ScoreViewModel

ScoreViewModel是页面视图的业务逻辑处理,如处理客户端的点击的命令等内容。具体代码如下所示:

  1 namespace SIMS.ScoreModule.ViewModels   2 {   3     public class ScoreViewModel : BindableBase   4     {   5    6         #region 属性或构造方法   7    8         /// <summary>   9         /// 课程名称  10         /// </summary>  11         private string courseName;  12   13         public string CourseName  14         {  15             get { return courseName; }  16             set { SetProperty(ref courseName, value); }  17         }  18   19         /// <summary>  20         /// 学生姓名  21         /// </summary>  22         private string studentName;  23   24         public string StudentName  25         {  26             get { return studentName; }  27             set { SetProperty(ref studentName, value); }  28         }  29   30         private ObservableCollection<ScoreInfo> scores;  31   32         public ObservableCollection<ScoreInfo> Scores  33         {  34             get { return scores; }  35             set { SetProperty(ref scores, value); }  36         }  37   38         private IDialogService dialogService;  39   40         public ScoreViewModel(IDialogService dialogService)  41         {  42             this.dialogService = dialogService;  43             this.pageNum = 1;  44             this.pageSize = 20;  45         }  46   47         private void InitInfo()  48         {  49             Scores = new ObservableCollection<ScoreInfo>();  50             var pagedRequst = ScoreHttpUtil.GetScores(this.StudentName, this.CourseName, this.pageNum, this.pageSize);  51             var entities = pagedRequst.items;  52             Scores.AddRange(entities.Select(r=>new ScoreInfo(r)));  53             //  54             this.TotalCount = pagedRequst.count;  55             this.TotalPage = ((int)Math.Ceiling(this.TotalCount * 1.0 / this.pageSize));  56         }  57   58         #endregion  59   60         #region 事件  61   62         private DelegateCommand loadedCommand;  63   64         public DelegateCommand LoadedCommand  65         {  66             get  67             {  68                 if (loadedCommand == null)  69                 {  70                     loadedCommand = new DelegateCommand(Loaded);  71                 }  72                 return loadedCommand;  73             }  74         }  75   76         private void Loaded()  77         {  78             InitInfo();  79         }  80   81         private DelegateCommand queryCommand;  82   83         public DelegateCommand QueryCommand  84         {  85             get  86             {  87                 if (queryCommand == null)  88                 {  89                     queryCommand = new DelegateCommand(Query);  90                 }  91                 return queryCommand;  92             }  93         }  94   95         private void Query()  96         {  97             this.pageNum = 1;  98             this.InitInfo();  99         } 100  101         /// <summary> 102         /// 新增命令 103         /// </summary> 104         private DelegateCommand addCommand; 105  106         public DelegateCommand AddCommand 107         { 108             get 109             { 110                 if (addCommand == null) 111                 { 112                     addCommand = new DelegateCommand(Add); 113                 } 114                 return addCommand; 115             } 116         } 117  118         private void Add() 119         { 120             this.dialogService.ShowDialog("addEditScore", null, AddEditCallBack, "MetroDialogWindow"); 121         } 122  123         private void AddEditCallBack(IDialogResult dialogResult) 124         { 125             if (dialogResult != null && dialogResult.Result == ButtonResult.OK) 126             { 127                 //刷新列表 128                 this.pageNum = 1; 129                 this.InitInfo(); 130             } 131         } 132  133         /// <summary> 134         /// 编辑命令 135         /// </summary> 136         private DelegateCommand<object> editCommand; 137  138         public DelegateCommand<object> EditCommand 139         { 140             get 141             { 142                 if (editCommand == null) 143                 { 144                     editCommand = new DelegateCommand<object>(Edit); 145                 } 146                 return editCommand; 147             } 148         } 149  150         private void Edit(object obj) 151         { 152             if (obj == null) 153             { 154                 return; 155             } 156             var Id = int.Parse(obj.ToString()); 157             var score = this.Scores.FirstOrDefault(r => r.Id == Id); 158             if (score == null) 159             { 160                 MessageBox.Show("无效的成绩ID"); 161                 return; 162             } 163             IDialogParameters dialogParameters = new DialogParameters(); 164             dialogParameters.Add("score", score); 165             this.dialogService.ShowDialog("addEditScore", dialogParameters, AddEditCallBack, "MetroDialogWindow"); 166         } 167  168         /// <summary> 169         /// 编辑命令 170         /// </summary> 171         private DelegateCommand<object> deleteCommand; 172  173         public DelegateCommand<object> DeleteCommand 174         { 175             get 176             { 177                 if (deleteCommand == null) 178                 { 179                     deleteCommand = new DelegateCommand<object>(Delete); 180                 } 181                 return deleteCommand; 182             } 183         } 184  185         private void Delete(object obj) 186         { 187             if (obj == null) 188             { 189                 return; 190             } 191             var Id = int.Parse(obj.ToString()); 192             var score = this.Scores.FirstOrDefault(r => r.Id == Id); 193             if (score == null) 194             { 195                 MessageBox.Show("无效的成绩ID"); 196                 return; 197             } 198             if (MessageBoxResult.Yes != MessageBox.Show("Are you sure to delete?", "Confirm", MessageBoxButton.YesNo)) 199             { 200                 return; 201             } 202             bool flag = ScoreHttpUtil.DeleteScore(Id); 203             if (flag) 204             { 205                 this.pageNum = 1; 206                 this.InitInfo(); 207             } 208         } 209  210         #endregion 211     } 212 }

注意:关于分页功能,与其他模块代码通用,所以此处略去。

4. 3. 新增编辑成绩视图AddEditScore

新增编辑成绩视图,主要用于对成绩的修改和新增,可通过查询页面的新增按钮和具体成绩的编辑按钮弹出对应窗口。如下所示:

 1 <UserControl x:Class="SIMS.ScoreModule.Views.AddEditScore"  2              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  3              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  4              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"   5              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"   6              xmlns:local="clr-namespace:SIMS.ScoreModule.Views"  7              xmlns:i="http://schemas.microsoft.com/xaml/behaviors"  8              xmlns:mahApps ="http://metro.mahapps.com/winfx/xaml/controls"  9              xmlns:prism="http://prismlibrary.com/"       10              mc:Ignorable="d"  11              d:DesignHeight="450" d:DesignWidth="800"> 12     <prism:Dialog.WindowStyle> 13         <Style TargetType="Window"> 14             <Setter Property="Width" Value="600"></Setter> 15             <Setter Property="Height" Value="400"></Setter> 16         </Style> 17     </prism:Dialog.WindowStyle> 18     <UserControl.Resources> 19         <ResourceDictionary> 20             <ResourceDictionary.MergedDictionaries> 21                 <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" /> 22                 <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Blue.xaml" /> 23             </ResourceDictionary.MergedDictionaries> 24         </ResourceDictionary> 25     </UserControl.Resources> 26     <i:Interaction.Triggers> 27         <i:EventTrigger EventName="Loaded"> 28             <i:InvokeCommandAction Command="{Binding LoadedCommand}"></i:InvokeCommandAction> 29         </i:EventTrigger> 30     </i:Interaction.Triggers> 31     <Grid> 32         <Grid.ColumnDefinitions> 33             <ColumnDefinition Width="0.2*"></ColumnDefinition> 34             <ColumnDefinition Width="Auto"></ColumnDefinition> 35             <ColumnDefinition Width="*"></ColumnDefinition> 36             <ColumnDefinition Width="0.2*"></ColumnDefinition> 37         </Grid.ColumnDefinitions> 38         <Grid.RowDefinitions> 39             <RowDefinition></RowDefinition> 40             <RowDefinition></RowDefinition> 41             <RowDefinition></RowDefinition> 42             <RowDefinition></RowDefinition> 43         </Grid.RowDefinitions> 44         <TextBlock Text="学生" Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" Margin="3"></TextBlock> 45         <ComboBox Grid.Row="0" Grid.Column="2" MinWidth="120" Height="35" ItemsSource="{Binding Students}" mahApps:TextBoxHelper.ClearTextButton="True" SelectedItem="{Binding Student}"> 46             <ComboBox.ItemTemplate> 47                 <DataTemplate> 48                     <TextBlock Text="{Binding Name}"></TextBlock> 49                 </DataTemplate> 50             </ComboBox.ItemTemplate> 51         </ComboBox> 52         <TextBlock Text="课程" Grid.Row="1" Grid.Column="1"  VerticalAlignment="Center" Margin="3"></TextBlock> 53         <ComboBox Grid.Row="1" Grid.Column="2" MinWidth="120" Height="35" ItemsSource="{Binding Courses}" mahApps:TextBoxHelper.ClearTextButton="True" SelectedItem="{Binding Course}"> 54             <ComboBox.ItemTemplate> 55                 <DataTemplate> 56                     <TextBlock Text="{Binding Name}"></TextBlock> 57                 </DataTemplate> 58             </ComboBox.ItemTemplate> 59         </ComboBox> 60         <TextBlock Text="成绩" Grid.Row="2" Grid.Column="1"   VerticalAlignment="Center" Margin="3"></TextBlock> 61         <TextBox Grid.Row="2" Grid.Column="2" MinWidth="120" Height="35"   VerticalAlignment="Center" Margin="3" Text="{Binding Score.Score}"></TextBox> 62         <StackPanel Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Center" Margin="3"> 63             <Button Content="取消" Margin="5" MinWidth="120" Height="35" Style="{DynamicResource MahApps.Styles.Button.Square.Accent}" Command="{Binding CancelCommand}"></Button> 64             <Button Content="保存" Margin="5" MinWidth="120" Height="35" Style="{DynamicResource MahApps.Styles.Button.Square.Accent}" Command="{Binding SaveCommand}"></Button> 65         </StackPanel> 66     </Grid> 67 </UserControl>

4. 新增编辑成绩ViewModel

AddEditScoreViewModel是对页面具体功能的业务封装,主要是对应成绩信息的保存,也包括数据绑定和命令绑定等内容,与其他模块不同之处,在于此模块关联学生和课程信息,需要绑定下拉框数据源。具体如下所示:

  1 namespace SIMS.ScoreModule.ViewModels   2 {   3     public class AddEditScoreViewModel : BindableBase, IDialogAware   4     {   5    6         #region 属性和构造函数   7    8         /// <summary>   9         /// 当前实体  10         /// </summary>  11         private ScoreEntity score;  12   13         public ScoreEntity Score  14         {  15             get { return score; }  16             set { SetProperty(ref score , value); }  17         }  18   19   20         /// <summary>  21         /// 下拉框选择的学生  22         /// </summary>  23         private StudentEntity student;  24   25         public StudentEntity Student  26         {  27             get { return student; }  28             set { SetProperty(ref student , value); }  29         }  30   31         /// <summary>  32         /// 学生列表  33         /// </summary>  34         private List<StudentEntity> students;  35   36         public List<StudentEntity> Students  37         {  38             get { return students; }  39             set { SetProperty(ref students, value); }  40         }  41   42         private CourseEntity course;  43   44         public CourseEntity Course  45         {  46             get { return course; }  47             set {SetProperty(ref course , value); }  48         }  49   50   51         /// <summary>  52         /// 课程列表  53         /// </summary>  54         private List<CourseEntity> courses;  55   56         public List<CourseEntity> Courses  57         {  58             get { return courses; }  59             set { SetProperty(ref courses, value); }  60         }  61   62         public AddEditScoreViewModel() {   63           64         }  65   66   67         #endregion  68   69         #region Command  70   71         private DelegateCommand loadedCommand;  72   73         public DelegateCommand LoadedCommand  74         {  75             get  76             {  77                 if (loadedCommand == null)  78                 {  79                     loadedCommand = new DelegateCommand(Loaded);  80                 }  81                 return loadedCommand;  82             }  83         }  84   85         private void Loaded()  86         {  87             LoadStudents();  88             LoadCourses();  89   90             //如果有班长,则为班长赋值  91             if (Score.StudentId > 0)  92             {  93                 this.Student = this.Students?.FirstOrDefault(r => r.Id == Score.StudentId);  94             }  95             if (Score.CourseId > 0) {   96                 this.Course = this.Courses?.FirstOrDefault(r=>r.Id == Score.CourseId);  97             }  98         }  99  100  101         private DelegateCommand cancelCommand; 102  103         public DelegateCommand CancelCommand 104         { 105             get 106             { 107                 if (cancelCommand == null) 108                 { 109                     cancelCommand = new DelegateCommand(Cancel); 110                 } 111                 return cancelCommand; 112             } 113         } 114  115         private void Cancel() 116         { 117             RequestClose?.Invoke((new DialogResult(ButtonResult.Cancel))); 118         } 119  120         private DelegateCommand saveCommand; 121  122         public DelegateCommand SaveCommand 123         { 124             get 125             { 126                 if (saveCommand == null) 127                 { 128                     saveCommand = new DelegateCommand(Save); 129                 } 130                 return saveCommand; 131             } 132         } 133  134         private void Save() 135         { 136             if (Score != null) 137             { 138                 Score.CreateTime = DateTime.Now; 139                 Score.LastEditTime = DateTime.Now; 140                 if (Student != null) 141                 { 142                     Score.StudentId = Student.Id; 143                 } 144                 if (Course != null) {  145                     Score.CourseId = Course.Id; 146                 } 147                 bool flag = false; 148                 if (Score.Id > 0) 149                 { 150                     flag = ScoreHttpUtil.UpdateScore(Score); 151                 } 152                 else 153                 { 154                     flag = ScoreHttpUtil.AddScore(Score); 155                 } 156                 if (flag) 157                 { 158                     RequestClose?.Invoke((new DialogResult(ButtonResult.OK))); 159                 } 160             } 161         } 162  163  164         #endregion 165  166         #region 函数 167  168         /// <summary> 169         /// 加载学生列表 170         /// </summary> 171         private void LoadStudents() { 172             this.Students = new List<StudentEntity>(); 173             var pagedRequst = StudentHttpUtil.GetStudents(null, null, 1, -1); 174             var entities = pagedRequst.items; 175             Students.AddRange(entities); 176         } 177  178         /// <summary> 179         /// 加载课程列表 180         /// </summary> 181         private void LoadCourses() { 182             this.Courses = new List<CourseEntity>(); 183             var pagedRequst = CourseHttpUtil.GetCourses(null, null, 1, -1); 184             var entities = pagedRequst.items; 185             Courses.AddRange(entities); 186         } 187  188         #endregion 189     } 190 }

注意:弹出窗口实现方法与其他模块通用,所以此处略去。

5. 成绩管理示例效果图

经过上述步骤后,成绩管理模块就开发完成,运行VS后,效果如下所示:

WPF开发学生信息管理系统【WPF+Prism+MAH+WebApi】(完)

系统管理模块

1. 系统管理模块核心代码

系统管理模块,主要包含四个部分,用户管理,角色管理,菜单管理,个人信息。因篇幅有限,暂时仅列出主要内容:

从数据库读取用户所属的权限,代码如下所示:

 1 public List<UserRight> GetUserRights(int? userId)  2 {  3     if (userId != null)  4     {  5         var query = from u in dataContext.UserRoles  6                     join r in dataContext.Roles on u.RoleId equals r.Id  7                     join x in dataContext.RoleMenus on r.Id equals x.RoleId  8                     join m in dataContext.Menus on x.MenuId equals m.Id  9                     where u.UserId == userId 10                     select new UserRight { Id = m.Id, RoleName = r.Name, MenuName = m.Name, Url = m.Url,Icon=m.Icon, ParentId = m.ParentId, SortId = m.SortId }; 11  12         return query.ToList(); 13     } 14     return null; 15 }

在客户端获取后,转换成导航菜单对象即可,如下所示:

 1 public NavigationViewModel(IEventAggregator eventAggregator)  2 {  3     this.eventAggregator = eventAggregator;  4     navItems = new List<HamburgerMenuItemBase>();  5     var userRights = RoleHttpUtil.GetUserRights(UserInfo.Instance.Id);  6     var parents = userRights.Where(x => x.ParentId == null).OrderBy(r=>r.SortId);  7     foreach (var parent in parents) {  8         navItems.Add(new HamburgerMenuHeaderItem() { Label = parent.MenuName });  9         var subItems = userRights.Where(r=>r.ParentId==parent.Id).OrderBy(r=>r.SortId); 10         foreach (var subItem in subItems) { 11             navItems.Add(new HamburgerMenuGlyphItem() { Label = subItem.MenuName, Tag = subItem.Url, Glyph = subItem.Icon }); 12         } 13     } 14     UserInfo.Instance.Roles = String.Join(',', userRights.Select(r=>r.RoleName).Distinct().ToList()); 15 }

2. 系统管理模块示例截图

关于系统管理模块示例截图如下所示:

个人信息,显示个人基础信息,如下所示:

WPF开发学生信息管理系统【WPF+Prism+MAH+WebApi】(完)

 

 用户管理,比其他列表多了一个授权按钮,主要用于为用户分配角色如下所示:

WPF开发学生信息管理系统【WPF+Prism+MAH+WebApi】(完)

角色管理模块,比其他列表多了一个分配按钮,主要用于为分配角色对应的菜单如下所示:

WPF开发学生信息管理系统【WPF+Prism+MAH+WebApi】(完)

菜单管理,菜单管理模块,主要用于管理菜单信息,与其他模块不同的是,需要配置图标,如下所示:

WPF开发学生信息管理系统【WPF+Prism+MAH+WebApi】(完)

总结

通过本篇文章的成绩管理模块,系统管理模块,以及前两篇文章中的课程管理模块,班级管理模块,学生管理模块,不难发现,每一个模块的开发都是由列表DataGrid,文本框TextBox,下拉框Combox,单选按钮RadioButton,按钮Button等组成的,虽功能略有差异,但总归万变不离其宗。开发方法也大同小异,复杂的功能都是普通的功能累加起来的。这也是本系列文章由浅入深的渐进安排。希望能够抛砖引玉,不局限于某一功能,而是能够举一反三,自我理解,以达到自我开发的能力。

至此,整个学生信息管理系统系列已完毕。

 

关于源码

关于源码下载,可点击CSDN上的链接 或者关注个人公众号【老码识途】进行下载,如下所示:

WPF开发学生信息管理系统【WPF+Prism+MAH+WebApi】(完)WPF开发学生信息管理系统【WPF+Prism+MAH+WebApi】(完)编辑