最近通過WPF開發專案,為了對WPF知識點進行總結,所以利用業余時間,開發一個學生資訊管理系統【Student Information Management System】,前四篇文章進行了框架搭建和模塊劃分,后臺WebApi介面撰寫,以及課程管理模塊,班級管理模塊,學生管理模塊的開發,本文在前四篇基礎之上,繼續深入開發學生資訊管理系統的成績管理和系統管理模塊,通過本篇文章,將繼續鞏固之前的知識點,本文僅供學習分享使用,如有不足之處,還請指正,
涉及知識點
學生資訊管理系統SIMS屬于一個小型的完整系統開發,涉及的知識點比較,具體如下所示:
- WPF開發中TextBlock,TextBox,DataGrid,Combox,TabControl等控制元件的基礎使用以及資料系結等操作,
- MAH樣式的使用,在本示例中MAH主要用于統一頁面風格,提高用戶體驗,
- HttpClient使用,主要用于訪問服務端提供的介面,
業務邏輯
前面幾篇文章,由淺入深,逐步介紹了課程管理模塊,班級管理模塊,學生管理模塊,今天繼續介紹成績管理模塊,業務邏輯關系如下:
- 學生屬于某一班級之學生,所以學生中包含班級資訊,
- 班級中存在班長,同時班長又屬于學生的一個物體,
- 成績是某一學生的成績,且一名學生有各門課程的成績,所以成績和學生有關,且和課程有關,
物體E-R圖
學生表,成績表,班級表,課程表,各個資料表之間的E-R圖,如下所示:

由此可見,成績表與課程和學生表,都有關聯,所以放在最后,
成績管理
成績管理主要用于錄入各個學生各個課程的成績,包含成績表的增刪改查功能,
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還每一個控制器都進行歸類,可以清晰的看到每一個介面對應的網址,成績管理模塊對應的介面如下所示:

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 = https://www.cnblogs.com/hsiang/archive/2022/06/05/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 = https://www.cnblogs.com/hsiang/archive/2022/06/05/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 = https://www.cnblogs.com/hsiang/archive/2022/06/05/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,如下所示:
- Score視圖,主要用于成績的查詢,以及新增,修改,洗掉的鏈接入口,
- AddEditScore視圖,主要用于成績資訊的新增和修改,共用一個視圖頁面,
- 成績課程不需要頁面,所以沒有對應視圖,
4.1. Score視圖
Score視圖,主要是成績的查詢和新增,修改,洗掉的鏈接入口,涉及知識點如下:
- Score視圖頁面布局采用Grid方式和StackPanel混合布局,即整體布局采用Grid,細微布局采用StackPanel,
- 成績采用分頁串列的方式展示,需要用到DataGrid,及分頁控制元件【WPF默認不提供分頁控制元件,可自行撰寫分頁控制元件】,
- 查詢條件采用按鈕Button和文本框TextBox等組成,關于基礎控制元件的使用,不再詳細論述,可參考其他文章,
- 在本系統的所有WPF視圖中,均需要引入Prism和 MAH組件,
- 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后,效果如下所示:

系統管理模塊
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. 系統管理模塊示例截圖
關于系統管理模塊示例截圖如下所示:
個人資訊,顯示個人基礎資訊,如下所示:

用戶管理,比其他串列多了一個授權按鈕,主要用于為用戶分配角色如下所示:

角色管理模塊,比其他串列多了一個分配按鈕,主要用于為分配角色對應的選單如下所示:

選單管理,選單管理模塊,主要用于管理選單資訊,與其他模塊不同的是,需要配置圖示,如下所示:

總結
通過本篇文章的成績管理模塊,系統管理模塊,以及前兩篇文章中的課程管理模塊,班級管理模塊,學生管理模塊,不難發現,每一個模塊的開發都是由串列DataGrid,文本框TextBox,下拉框Combox,單選按鈕RadioButton,按鈕Button等組成的,雖功能略有差異,但總歸萬變不離其宗,開發方法也大同小異,復雜的功能都是普通的功能累加起來的,這也是本系列文章由淺入深的漸進安排,希望能夠拋磚引玉,不局限于某一功能,而是能夠舉一反三,自我理解,以達到自我開發的能力,
至此,整個學生資訊管理系統系列已完畢,
?
關于原始碼
關于原始碼下載,可點擊CSDN上的鏈接 或者關注個人公眾號【老碼識途】進行下載,如下所示:

?編輯
作者:小六公子
出處:http://www.cnblogs.com/hsiang/
本文著作權歸作者和博客園共有,寫文不易,支持原創,歡迎轉載【點贊】,轉載請保留此段宣告,且在文章頁面明顯位置給出原文連接,謝謝,
關注個人公眾號,定時同步更新技術及職場文章
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/486148.html
標籤:.NET技术
下一篇:驅動開發實戰之TcpClient
