主頁 > .NET開發 > WPF開發學生資訊管理系統【WPF+Prism+MAH+WebApi】(完)

WPF開發學生資訊管理系統【WPF+Prism+MAH+WebApi】(完)

2022-06-06 07:49:01 .NET開發

最近通過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介面是對成績管理的抽象,如下所示:

 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,如下所示:

  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后,效果如下所示:

系統管理模塊

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技术

上一篇:VisualStudio-檔案未顯示在右側

下一篇:驅動開發實戰之TcpClient

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more