最近通过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图,如下所示:

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

成绩管理

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

1. 成绩管理后台服务Service

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

namespace SIMS.WebApi.Services.Score
{public interface IScoreAppService{public PagedRequest<ScoreEntity> GetScores(string studentName,string courseName,int pageNum,int pageSize);/// <summary>/// 通过id查询成绩信息/// </summary>/// <param name="id"></param>/// <returns></returns>public ScoreEntity GetScore(int id);/// <summary>/// 新增成绩/// </summary>/// <param name="score"></param>/// <returns></returns>public int AddScore(ScoreEntity score);/// <summary>/// 修改成绩/// </summary>/// <param name="score"></param>/// <returns></returns>public int UpdateScore(ScoreEntity score);/// <summary>/// 删除成绩/// </summary>/// <param name="id"></param>public int DeleteScore(int id);}
}

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

namespace SIMS.WebApi.Services.Score
{public class ScoreAppService : IScoreAppService{private DataContext dataContext;public ScoreAppService(DataContext dataContext){this.dataContext = dataContext;}public int AddScore(ScoreEntity score){var entity = this.dataContext.Scores.Add(score);this.dataContext.SaveChanges();return 0;}public int DeleteScore(int id){var entity = dataContext.Scores.FirstOrDefault(x => x.Id == id);if (entity != null){dataContext.Scores.Remove(entity);dataContext.SaveChanges();}return 0;}public ScoreEntity GetScore(int id){var entity = dataContext.Scores.FirstOrDefault(r => r.Id == id);return entity;}/// <summary>/// 按条件查询成绩列表/// </summary>/// <param name="studentName"></param>/// <param name="courseName"></param>/// <param name="pageNum"></param>/// <param name="pageSize"></param>/// <returns></returns>public PagedRequest<ScoreEntity> GetScores(string studentName, string courseName, int pageNum, int pageSize){IQueryable<ScoreEntity> scores = null;if (!string.IsNullOrEmpty(studentName) && !string.IsNullOrEmpty(courseName)){var students = this.dataContext.Students.Where(r => r.Name.Contains(studentName));var courses = this.dataContext.Courses.Where(r => r.Name.Contains(courseName));scores = this.dataContext.Scores.Where(r => students.Select(t => t.Id).Contains(r.StudentId)).Where(r => courses.Select(t => t.Id).Contains(r.CourseId));}else if (!string.IsNullOrEmpty(studentName)){var students = this.dataContext.Students.Where(r => r.Name.Contains(studentName));scores = this.dataContext.Scores.Where(r => students.Select(t => t.Id).Contains(r.StudentId));}else if (!string.IsNullOrEmpty(courseName)){var courses = this.dataContext.Courses.Where(r => r.Name.Contains(courseName));scores = this.dataContext.Scores.Where(r => courses.Select(t => t.Id).Contains(r.CourseId));}else {scores = dataContext.Scores.Where(r => true).OrderBy(r => r.Id);}int count = scores.Count();List<ScoreEntity> items;if (pageSize > 0){items = scores.Skip((pageNum - 1) * pageSize).Take(pageSize).ToList();}else{items = scores.ToList();}return new PagedRequest<ScoreEntity>(){count = count,items = items};}public int UpdateScore(ScoreEntity score){dataContext.Scores.Update(score);dataContext.SaveChanges();return 0;}}
}

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

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

namespace SIMS.WebApi.Controllers
{/// <summary>/// 成绩控制器/// </summary>[Route("api/[controller]/[action]")][ApiController]public class ScoreController : ControllerBase{private readonly ILogger<ScoreController> logger;private readonly IScoreAppService scoreAppService;public ScoreController(ILogger<ScoreController> logger, IScoreAppService scoreAppService){this.logger = logger;this.scoreAppService = scoreAppService;}/// <summary>/// 获取成绩信息/// </summary>/// <param name="id"></param>/// <returns></returns>[HttpGet]public PagedRequest<ScoreEntity> GetScores(string? studentName, string? courseName, int pageNum, int pageSize){return scoreAppService.GetScores(studentName, courseName, pageNum, pageSize);}/// <summary>/// 获取成绩信息/// </summary>/// <param name="id"></param>/// <returns></returns>[HttpGet]public ScoreEntity GetScore(int id){return scoreAppService.GetScore(id);}/// <summary>/// 新增成绩/// </summary>/// <param name="score"></param>/// <returns></returns>[HttpPost]public int AddScore(ScoreEntity score){return scoreAppService.AddScore(score);}/// <summary>/// 修改成绩/// </summary>/// <param name="score"></param>/// <returns></returns>[HttpPut]public int UpdateScore(ScoreEntity score){return scoreAppService.UpdateScore(score);}/// <summary>/// 删除成绩/// </summary>/// <param name="id"></param>[HttpDelete]public int DeleteScore(int id){return scoreAppService.DeleteScore(id);}}
}

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

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

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

namespace SIMS.Utils.Http
{public class ScoreHttpUtil:HttpUtil{/// <summary>/// 通过id查询成绩信息/// </summary>/// <param name="id"></param>/// <returns></returns>public static ScoreEntity GetScore(int id){Dictionary<string, object> data = new Dictionary<string, object>();data["id"] = id;var str = Get(UrlConfig.SCORE_GETSCORE, data);var socre = StrToObject<ScoreEntity>(str);return socre;}/// <summary>////// </summary>/// <param name="studentName"></param>/// <param name="courseName"></param>/// <param name="pageNum"></param>/// <param name="pageSize"></param>/// <returns></returns>public static PagedRequest<ScoreEntity> GetScores(string? studentName, string? courseName, int pageNum, int pageSize){Dictionary<string, object> data = new Dictionary<string, object>();data["courseName"] = courseName;data["studentName"] = studentName;data["pageNum"] = pageNum;data["pageSize"] = pageSize;var str = Get(UrlConfig.SCORE_GETSCORES, data);var socres = StrToObject<PagedRequest<ScoreEntity>>(str);return socres;}public static bool AddScore(ScoreEntity socre){var ret = Post<ScoreEntity>(UrlConfig.SCORE_ADDSCORE, socre);return int.Parse(ret) == 0;}public static bool UpdateScore(ScoreEntity socre){var ret = Put<ScoreEntity>(UrlConfig.SCORE_UPDATESCORE, socre);return int.Parse(ret) == 0;}public static bool DeleteScore(int Id){Dictionary<string, string> data = new Dictionary<string, string>();data["Id"] = Id.ToString();var ret = Delete(UrlConfig.SCORE_DELETESCORE, data);return int.Parse(ret) == 0;}}
}

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视图具体代码,如下所示:

<UserControl x:Class="SIMS.ScoreModule.Views.Score"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:i="http://schemas.microsoft.com/xaml/behaviors"xmlns:prism="http://prismlibrary.com/"xmlns:local="clr-namespace:SIMS.ScoreModule.Views"mc:Ignorable="d"xmlns:mahApps="http://metro.mahapps.com/winfx/xaml/controls"xmlns:ctrls ="clr-namespace:SIMS.Utils.Controls;assembly=SIMS.Utils"prism:ViewModelLocator.AutoWireViewModel="True"d:DesignHeight="450" d:DesignWidth="800"><UserControl.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" /><ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Blue.xaml" /><ResourceDictionary><Style x:Key="LinkButton" TargetType="Button"><Setter Property="Background" Value="White"></Setter><Setter Property="Cursor" Value="Hand"></Setter><Setter Property="Margin" Value="3"></Setter><Setter Property="MinWidth" Value="80"></Setter><Setter Property="MinHeight" Value="25"></Setter><Setter Property="BorderThickness" Value="0 0 0 0"></Setter></Style></ResourceDictionary></ResourceDictionary.MergedDictionaries></ResourceDictionary></UserControl.Resources><i:Interaction.Triggers><i:EventTrigger EventName="Loaded"><i:InvokeCommandAction Command="{Binding LoadedCommand}"></i:InvokeCommandAction></i:EventTrigger></i:Interaction.Triggers><Grid><Grid.RowDefinitions><RowDefinition Height="Auto"></RowDefinition><RowDefinition Height="Auto"></RowDefinition><RowDefinition Height="*"></RowDefinition><RowDefinition Height="Auto"></RowDefinition></Grid.RowDefinitions><TextBlock Text="成绩信息" FontSize="20" Background="AliceBlue" Margin="2"></TextBlock><StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Center"><TextBlock Text="学生名称" VerticalAlignment="Center" Margin="2"></TextBlock><TextBox Margin="4" MinWidth="120" Height="30"Text="{Binding StudentName}"HorizontalContentAlignment="Stretch"mahApps:TextBoxHelper.ClearTextButton="True"mahApps:TextBoxHelper.Watermark="学生名称"mahApps:TextBoxHelper.WatermarkAlignment="Left"SpellCheck.IsEnabled="True" /><TextBlock Text="课程名称" VerticalAlignment="Center" Margin="2"></TextBlock><TextBox Margin="4" MinWidth="120" Height="30"Text="{Binding CourseName}"HorizontalContentAlignment="Stretch"mahApps:TextBoxHelper.ClearTextButton="True"mahApps:TextBoxHelper.Watermark="课程名称"mahApps:TextBoxHelper.WatermarkAlignment="Left"SpellCheck.IsEnabled="True" /><Button Content="查询" Style="{DynamicResource MahApps.Styles.Button.Square.Accent}" Width="120" Height="30" Margin="3" Command="{Binding QueryCommand}"></Button><Button Content="新增" Style="{DynamicResource MahApps.Styles.Button.Square.Accent}" Width="120" Height="30" Margin="3" Command="{Binding AddCommand}"></Button></StackPanel><DataGrid x:Name="dgScores"Grid.Row="2"Grid.Column="0"Margin="2"AutoGenerateColumns="False"CanUserAddRows="False"CanUserDeleteRows="False"ItemsSource="{Binding Scores}"RowHeaderWidth="0"><DataGrid.Columns><DataGridTextColumn Binding="{Binding Student.Name}" Header="学生" Width="*" /><DataGridTextColumn Binding="{Binding Course.Name}" Header="课程" Width="*"/><DataGridTextColumn Binding="{Binding Score}" Header="成绩" Width="*"/><DataGridTextColumn Binding="{Binding CreateTime, StringFormat=yyyy-MM-dd HH:mm:ss}" Header="创建时间" Width="*"/><DataGridTextColumn Binding="{Binding LastEditTime,StringFormat=yyyy-MM-dd HH:mm:ss}" Header="最后修改时间" Width="*"/><DataGridTemplateColumn Header="操作" Width="*"><DataGridTemplateColumn.CellTemplate><DataTemplate><StackPanel Orientation="Horizontal"><Button  Content="Edit" Style="{StaticResource LinkButton}" Command="{Binding RelativeSource={RelativeSource  AncestorType=DataGrid,  Mode=FindAncestor}, Path=DataContext.EditCommand}" CommandParameter="{Binding Id}"><Button.Template><ControlTemplate TargetType="Button"><TextBlock TextDecorations="Underline" HorizontalAlignment="Center"><ContentPresenter /></TextBlock></ControlTemplate></Button.Template></Button><Button Content="Delete" Style="{StaticResource LinkButton}" Command="{Binding RelativeSource={RelativeSource  AncestorType=DataGrid,  Mode=FindAncestor}, Path=DataContext.DeleteCommand}" CommandParameter="{Binding Id}"><Button.Template><ControlTemplate TargetType="Button"><TextBlock TextDecorations="Underline" HorizontalAlignment="Center"><ContentPresenter /></TextBlock></ControlTemplate></Button.Template></Button></StackPanel></DataTemplate></DataGridTemplateColumn.CellTemplate></DataGridTemplateColumn></DataGrid.Columns></DataGrid><ctrls:PageControl Grid.Row="3" DataContext="{Binding}" ></ctrls:PageControl></Grid>
</UserControl>

4.2. ScoreViewModel

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

namespace SIMS.ScoreModule.ViewModels
{public class ScoreViewModel : BindableBase{#region 属性或构造方法/// <summary>/// 课程名称/// </summary>private string courseName;public string CourseName{get { return courseName; }set { SetProperty(ref courseName, value); }}/// <summary>/// 学生姓名/// </summary>private string studentName;public string StudentName{get { return studentName; }set { SetProperty(ref studentName, value); }}private ObservableCollection<ScoreInfo> scores;public ObservableCollection<ScoreInfo> Scores{get { return scores; }set { SetProperty(ref scores, value); }}private IDialogService dialogService;public ScoreViewModel(IDialogService dialogService){this.dialogService = dialogService;this.pageNum = 1;this.pageSize = 20;}private void InitInfo(){Scores = new ObservableCollection<ScoreInfo>();var pagedRequst = ScoreHttpUtil.GetScores(this.StudentName, this.CourseName, this.pageNum, this.pageSize);var entities = pagedRequst.items;Scores.AddRange(entities.Select(r=>new ScoreInfo(r)));//this.TotalCount = pagedRequst.count;this.TotalPage = ((int)Math.Ceiling(this.TotalCount * 1.0 / this.pageSize));}#endregion#region 事件private DelegateCommand loadedCommand;public DelegateCommand LoadedCommand{get{if (loadedCommand == null){loadedCommand = new DelegateCommand(Loaded);}return loadedCommand;}}private void Loaded(){InitInfo();}private DelegateCommand queryCommand;public DelegateCommand QueryCommand{get{if (queryCommand == null){queryCommand = new DelegateCommand(Query);}return queryCommand;}}private void Query(){this.pageNum = 1;this.InitInfo();}/// <summary>/// 新增命令/// </summary>private DelegateCommand addCommand;public DelegateCommand AddCommand{get{if (addCommand == null){addCommand = new DelegateCommand(Add);}return addCommand;}}private void Add(){this.dialogService.ShowDialog("addEditScore", null, AddEditCallBack, "MetroDialogWindow");}private void AddEditCallBack(IDialogResult dialogResult){if (dialogResult != null && dialogResult.Result == ButtonResult.OK){//刷新列表this.pageNum = 1;this.InitInfo();}}/// <summary>/// 编辑命令/// </summary>private DelegateCommand<object> editCommand;public DelegateCommand<object> EditCommand{get{if (editCommand == null){editCommand = new DelegateCommand<object>(Edit);}return editCommand;}}private void Edit(object obj){if (obj == null){return;}var Id = int.Parse(obj.ToString());var score = this.Scores.FirstOrDefault(r => r.Id == Id);if (score == null){MessageBox.Show("无效的成绩ID");return;}IDialogParameters dialogParameters = new DialogParameters();dialogParameters.Add("score", score);this.dialogService.ShowDialog("addEditScore", dialogParameters, AddEditCallBack, "MetroDialogWindow");}/// <summary>/// 编辑命令/// </summary>private DelegateCommand<object> deleteCommand;public DelegateCommand<object> DeleteCommand{get{if (deleteCommand == null){deleteCommand = new DelegateCommand<object>(Delete);}return deleteCommand;}}private void Delete(object obj){if (obj == null){return;}var Id = int.Parse(obj.ToString());var score = this.Scores.FirstOrDefault(r => r.Id == Id);if (score == null){MessageBox.Show("无效的成绩ID");return;}if (MessageBoxResult.Yes != MessageBox.Show("Are you sure to delete?", "Confirm", MessageBoxButton.YesNo)){return;}bool flag = ScoreHttpUtil.DeleteScore(Id);if (flag){this.pageNum = 1;this.InitInfo();}}#endregion}
}

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

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

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

<UserControl x:Class="SIMS.ScoreModule.Views.AddEditScore"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:local="clr-namespace:SIMS.ScoreModule.Views"xmlns:i="http://schemas.microsoft.com/xaml/behaviors"xmlns:mahApps ="http://metro.mahapps.com/winfx/xaml/controls"xmlns:prism="http://prismlibrary.com/"mc:Ignorable="d"d:DesignHeight="450" d:DesignWidth="800"><prism:Dialog.WindowStyle><Style TargetType="Window"><Setter Property="Width" Value="600"></Setter><Setter Property="Height" Value="400"></Setter></Style></prism:Dialog.WindowStyle><UserControl.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" /><ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Blue.xaml" /></ResourceDictionary.MergedDictionaries></ResourceDictionary></UserControl.Resources><i:Interaction.Triggers><i:EventTrigger EventName="Loaded"><i:InvokeCommandAction Command="{Binding LoadedCommand}"></i:InvokeCommandAction></i:EventTrigger></i:Interaction.Triggers><Grid><Grid.ColumnDefinitions><ColumnDefinition Width="0.2*"></ColumnDefinition><ColumnDefinition Width="Auto"></ColumnDefinition><ColumnDefinition Width="*"></ColumnDefinition><ColumnDefinition Width="0.2*"></ColumnDefinition></Grid.ColumnDefinitions><Grid.RowDefinitions><RowDefinition></RowDefinition><RowDefinition></RowDefinition><RowDefinition></RowDefinition><RowDefinition></RowDefinition></Grid.RowDefinitions><TextBlock Text="学生" Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" Margin="3"></TextBlock><ComboBox Grid.Row="0" Grid.Column="2" MinWidth="120" Height="35" ItemsSource="{Binding Students}" mahApps:TextBoxHelper.ClearTextButton="True" SelectedItem="{Binding Student}"><ComboBox.ItemTemplate><DataTemplate><TextBlock Text="{Binding Name}"></TextBlock></DataTemplate></ComboBox.ItemTemplate></ComboBox><TextBlock Text="课程" Grid.Row="1" Grid.Column="1"  VerticalAlignment="Center" Margin="3"></TextBlock><ComboBox Grid.Row="1" Grid.Column="2" MinWidth="120" Height="35" ItemsSource="{Binding Courses}" mahApps:TextBoxHelper.ClearTextButton="True" SelectedItem="{Binding Course}"><ComboBox.ItemTemplate><DataTemplate><TextBlock Text="{Binding Name}"></TextBlock></DataTemplate></ComboBox.ItemTemplate></ComboBox><TextBlock Text="成绩" Grid.Row="2" Grid.Column="1"   VerticalAlignment="Center" Margin="3"></TextBlock><TextBox Grid.Row="2" Grid.Column="2" MinWidth="120" Height="35"   VerticalAlignment="Center" Margin="3" Text="{Binding Score.Score}"></TextBox><StackPanel Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Center" Margin="3"><Button Content="取消" Margin="5" MinWidth="120" Height="35" Style="{DynamicResource MahApps.Styles.Button.Square.Accent}" Command="{Binding CancelCommand}"></Button><Button Content="保存" Margin="5" MinWidth="120" Height="35" Style="{DynamicResource MahApps.Styles.Button.Square.Accent}" Command="{Binding SaveCommand}"></Button></StackPanel></Grid>
</UserControl>

4.4. 新增编辑成绩ViewModel

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

namespace SIMS.ScoreModule.ViewModels
{public class AddEditScoreViewModel : BindableBase, IDialogAware{#region 属性和构造函数/// <summary>/// 当前实体/// </summary>private ScoreEntity score;public ScoreEntity Score{get { return score; }set { SetProperty(ref score , value); }}/// <summary>/// 下拉框选择的学生/// </summary>private StudentEntity student;public StudentEntity Student{get { return student; }set { SetProperty(ref student , value); }}/// <summary>/// 学生列表/// </summary>private List<StudentEntity> students;public List<StudentEntity> Students{get { return students; }set { SetProperty(ref students, value); }}private CourseEntity course;public CourseEntity Course{get { return course; }set {SetProperty(ref course , value); }}/// <summary>/// 课程列表/// </summary>private List<CourseEntity> courses;public List<CourseEntity> Courses{get { return courses; }set { SetProperty(ref courses, value); }}public AddEditScoreViewModel() {}#endregion#region Commandprivate DelegateCommand loadedCommand;public DelegateCommand LoadedCommand{get{if (loadedCommand == null){loadedCommand = new DelegateCommand(Loaded);}return loadedCommand;}}private void Loaded(){LoadStudents();LoadCourses();//如果有班长,则为班长赋值if (Score.StudentId > 0){this.Student = this.Students?.FirstOrDefault(r => r.Id == Score.StudentId);}if (Score.CourseId > 0) {this.Course = this.Courses?.FirstOrDefault(r=>r.Id == Score.CourseId);}}private DelegateCommand cancelCommand;public DelegateCommand CancelCommand{get{if (cancelCommand == null){cancelCommand = new DelegateCommand(Cancel);}return cancelCommand;}}private void Cancel(){RequestClose?.Invoke((new DialogResult(ButtonResult.Cancel)));}private DelegateCommand saveCommand;public DelegateCommand SaveCommand{get{if (saveCommand == null){saveCommand = new DelegateCommand(Save);}return saveCommand;}}private void Save(){if (Score != null){Score.CreateTime = DateTime.Now;Score.LastEditTime = DateTime.Now;if (Student != null){Score.StudentId = Student.Id;}if (Course != null) {Score.CourseId = Course.Id;}bool flag = false;if (Score.Id > 0){flag = ScoreHttpUtil.UpdateScore(Score);}else{flag = ScoreHttpUtil.AddScore(Score);}if (flag){RequestClose?.Invoke((new DialogResult(ButtonResult.OK)));}}}#endregion#region 函数/// <summary>/// 加载学生列表/// </summary>private void LoadStudents() {this.Students = new List<StudentEntity>();var pagedRequst = StudentHttpUtil.GetStudents(null, null, 1, -1);var entities = pagedRequst.items;Students.AddRange(entities);}/// <summary>/// 加载课程列表/// </summary>private void LoadCourses() {this.Courses = new List<CourseEntity>();var pagedRequst = CourseHttpUtil.GetCourses(null, null, 1, -1);var entities = pagedRequst.items;Courses.AddRange(entities);}#endregion}
}

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

5. 成绩管理示例效果图

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

系统管理模块

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

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

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

public List<UserRight> GetUserRights(int? userId)
{if (userId != null){var query = from u in dataContext.UserRolesjoin r in dataContext.Roles on u.RoleId equals r.Idjoin x in dataContext.RoleMenus on r.Id equals x.RoleIdjoin m in dataContext.Menus on x.MenuId equals m.Idwhere u.UserId == userIdselect new UserRight { Id = m.Id, RoleName = r.Name, MenuName = m.Name, Url = m.Url,Icon=m.Icon, ParentId = m.ParentId, SortId = m.SortId };return query.ToList();}return null;
}

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

public NavigationViewModel(IEventAggregator eventAggregator)
{this.eventAggregator = eventAggregator;navItems = new List<HamburgerMenuItemBase>();var userRights = RoleHttpUtil.GetUserRights(UserInfo.Instance.Id);var parents = userRights.Where(x => x.ParentId == null).OrderBy(r=>r.SortId);foreach (var parent in parents) {navItems.Add(new HamburgerMenuHeaderItem() { Label = parent.MenuName });var subItems = userRights.Where(r=>r.ParentId==parent.Id).OrderBy(r=>r.SortId);foreach (var subItem in subItems) {navItems.Add(new HamburgerMenuGlyphItem() { Label = subItem.MenuName, Tag = subItem.Url, Glyph = subItem.Icon });}}UserInfo.Instance.Roles = String.Join(',', userRights.Select(r=>r.RoleName).Distinct().ToList());
}

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

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

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

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

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

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

总结

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

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

关于源码

关于源码下载,请点击链接

或者关注个人公众号【老码识途】进行下载,如下所示:

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

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

    最近通过WPF开发项目,为了对WPF知识点进行总结,所以利用业余时间,开发一个学生信息管理系统[Student Information Management System].本文主要简述如何通过WPF ...

  2. 基于JavaSwing开发学生信息管理系统(SQLServer数据库版本) 毕业设计 课程设计 大作业

    基于JavaSwing开发学生信息管理系统(SQLServer数据库版本):   (大作业) 开发环境: Windows操作系统 开发工具: MyEclipse+Jdk+SQLServer数据库 运行 ...

  3. 后端框架 Nest 入门教程: 开发学生信息管理系统

    作为一个前端,是否有想过学习下后端,做一个完整的应用? 如果你只是想体验下服务器端,可以选择 Express[1].它更容易上手.如果你想做一个企业级应用,推荐使用 Nest. Nest[2] (Ne ...

  4. Qt开发学生信息管理系统

    在本项目中,我们将使用Qt开发一个简单的学生信息管理系统,实现以下功能: 添加学生信息(姓名.学号.性别.年龄.班级): 显示学生信息列表: 根据学号或姓名搜索学生信息: 修改学生信息: 删除学生信息 ...

  5. 原生php开发学生信息管理系统源码

    主要功能: 1.班级管理 (1)添加班级:输入班级名称,选择系别,确认添加 (2)班级列表:班级列表显示,班级修改,删除班级,列表分页 2.学生管理 (1)添加学生:输入学生姓名,选择系别,选择班级名 ...

  6. Android应用开发-学生信息管理系统

    设计目的 1.网上很少有关于SQLite简单综合项目的测试APP. 2.把自己所学的部分UI综合一下,希望能给新手一些帮助. 涉及知识点 1.包括SQLite的增删查找等功能.查找中加入了" ...

  7. c语言学生信息系统 完整版,C语言 学生信息管理系统(完整版).docx

    C语言 学生信息管理系统(完整版) 电子科技大学成都学院 程序综合设计论文 论文题目 学生信息管理系统 学生姓名 魏国 学 号 1340840625 专 业 机械设计制造及其自动化 系(分院) 电子工 ...

  8. JSP+SQL基于JSP的学生信息管理系统(源代码+论文+答辩PPT)

    随着学校规模的不断扩大,学生数量急剧增加,有关学生的各种信息也成倍增长.面对如此庞大的信息量,开发学生信息管理系统来提高学生管理工作的效率就成为必然.通过该系统,可以做到信息的规范管理.科学统计和快速 ...

  9. C语言学生成绩管理系统文档版,C语言学生信息管理系统(完整版)总结.docx

    电子科技大学成都学院 程序综合设计论文 论文题目 学生信息管理系统 学生姓名 魏国 学 号 1340840625 专 业 机械设计制造及其自动化 系(分院) 电子工程系 授课教师 杜娥 2015年12 ...

最新文章

  1. 洛谷P2896 [USACO08FEB]一起吃饭Eating Together
  2. 解决ifconfig命令未找到
  3. linux教程 sed命令的用法,Linux文本处理三剑客——sed命令使用教程
  4. P2278 [HNOI2003]操作系统
  5. wps两列数据分别作为xy轴_0.4 秒,完成两列数据核对
  6. FFMPEG解码多线程
  7. miniui 样式第一次加载不出来_matplotlib--修改样式
  8. 联邦调查局严重夸大了加密威胁数字,从而想获得对手机的访问权限
  9. Ubuntu安装jdk10
  10. 配置Apache+Php+PDT(Zend Debugger)
  11. C/C++语法知识点汇总
  12. FPGA(七) PWM波
  13. excel数据分析 - 17个计算统计类函数
  14. 我为何从开发转测试,并坚持了16年?
  15. swot分析法案例_项目型销售案例剖析的五大步骤
  16. 小学计算机听课总评,小学听课评课评语大全
  17. 如何将整数数组转换为Zig-Zag格式?
  18. oeasy教您玩转vim - 59 - # 编辑总结
  19. android手机照片传苹果电脑版,为知笔记Android/iPhone客户端图片传到电脑客户端的方法介绍...
  20. SylixOS中APIC HPET定时器字符驱动实现

热门文章

  1. 系统集成项目管理工程师2020年下半年下午案例分析题及答案
  2. 自由天空XP/2K3封装工具 Easy Sysprep v2.0 正式版封装教程
  3. 主板BIOSCOMS故障解决三例
  4. 我的 Android 求职简历
  5. 大学生的小乐趣:HTML制作MacOS Dock栏
  6. 京东技术三面 +HR 面,成功拿到 30K offer 就职京东
  7. 紫外光刻胶 AR-N 4400/电子束光刻胶 AR-N7700/AR-P617 电子束光刻胶
  8. 地方社区(兰州论坛)成功运营 经典十问十答
  9. eclipse版本与jdk版本不匹配怎么办?
  10. 形状模式与路径查找器