Recently, through the WPF development project, in order to summarize the WPF knowledge points, I used my spare time to develop a student information management system [Student Information Management System]. The first three articles have carried out framework construction and module division, background WebApi interface writing, and course management module development. Based on the first three articles, this article continues to further develop the class management and student management modules of the student information management system. Through this article This article will continue to consolidate the previous knowledge points. This article is only for learning and sharing. If there are any shortcomings, please correct me.
Involving knowledge points
Since the server-side development of class management and student management will be introduced later in the second article, this article focuses on the development of client-side functions. The knowledge points involved are as follows:
- Basic use of controls such as TextBlock, TextBox, DataGrid, Combox, and data binding in WPF development.
- The use of MAH style, in this example, MAH is mainly used to unify page style and improve user experience.
- HttpClient is mainly used to access the interface provided by the server.
Business logic
First of all, class management and student management are both related and independent from each other, unlike the course management module that exists independently and does not depend on other modules. So the two modules are put together in one article to explain. The relationship is as follows:
- A student belongs to a class, so the class information is included in the student.
- There is a monitor in the class, and the monitor is an entity of the students.
class management
1. Interface access class ClassesHttpUtil
The class data table structure and service interface have been introduced in the second article. If you have any questions, you can go to the reference. The interface access class is used to encapsulate the interface provided by the access server. As follows:
1 namespace SIMS.Utils.Http 2 { 3 public class ClassesHttpUtil:HttpUtil 4 { 5 /// <summary> 6 /// pass id Inquire about student information 7 /// </summary> 8 /// <param name="id"></param> 9 /// <returns></returns> 10 public static ClassesEntity GetClasses(int id) 11 { 12 Dictionary<string, object> data = new Dictionary<string, object>(); 13 data["id"] = id; 14 var str = Get(UrlConfig.CLASSES_GETCLASSES, data); 15 var classes = StrToObject<ClassesEntity>(str); 16 return classes; 17 } 18 19 public static PagedRequest<ClassesEntity> GetClassess(string? dept, string? grade, int pageNum, int pageSize) 20 { 21 Dictionary<string, object> data = new Dictionary<string, object>(); 22 data["dept"] = dept; 23 data["grade"] = grade; 24 data["pageNum"] = pageNum; 25 data["pageSize"] = pageSize; 26 var str = Get(UrlConfig.CLASSES_GETCLASSESS, data); 27 var classess = StrToObject<PagedRequest<ClassesEntity>>(str); 28 return classess; 29 } 30 31 public static bool AddClasses(ClassesEntity classes) { 32 var ret = Post<ClassesEntity>(UrlConfig.CLASSES_ADDCLASSES, classes); 33 return int.Parse(ret)==0; 34 } 35 36 public static bool UpdateClasses(ClassesEntity classes) { 37 var ret = Put<ClassesEntity>(UrlConfig.CLASSES_UPDATECLASSES, classes); 38 return int.Parse(ret) == 0; 39 } 40 41 public static bool DeleteClasses(int Id) 42 { 43 Dictionary<string, string> data = new Dictionary<string, string>(); 44 data["Id"] = Id.ToString(); 45 var ret = Delete(UrlConfig.CLASSES_DELETECLASSES, data); 46 return int.Parse(ret) == 0; 47 } 48 } 49 }
2. Client page view
There are two client page views of class management, one is the query list page, and the other is the new editing page, which together constitute the addition, deletion, modification and query of the class management.
Query the class list page, the knowledge points involved are as follows:
- The query condition or the data column display in the list interacts with the ViewModel through data Binding, that is, click the query button, and no longer pass parameters, because the properties in the ViewModel have been updated synchronously.
- Not all properties in ViewModel can implement two-way binding, only properties with notification function can be implemented. In the Prism framework, it can be quickly implemented through the SetProperty method of BindableBase.
- In the View view, if there is a Command command in the control, it can be bound directly. If it does not exist, the event can be converted into a command by i:Interaction.Triggers, such as the Load event.
- In the list, if you need to add buttons, you can customize the data through DataTemplate.
Query the class page code as follows:
1 <UserControl x:Class="SIMS.ClassesModule.Views.Classes" 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.ClassesModule.Views" 7 xmlns:prism="http://prismlibrary.com/" 8 xmlns:i="http://schemas.microsoft.com/xaml/behaviors" 9 xmlns:mahApps="http://metro.mahapps.com/winfx/xaml/controls" 10 xmlns:ctrls ="clr-namespace:SIMS.Utils.Controls;assembly=SIMS.Utils" 11 prism:ViewModelLocator.AutoWireViewModel="True" 12 mc:Ignorable="d" 13 d:DesignHeight="450" d:DesignWidth="800"> 14 <UserControl.Resources> 15 <ResourceDictionary> 16 <ResourceDictionary.MergedDictionaries> 17 <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" /> 18 <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Blue.xaml" /> 19 <ResourceDictionary> 20 <Style x:Key="LinkButton" TargetType="Button"> 21 <Setter Property="Background" Value="White"></Setter> 22 <Setter Property="Cursor" Value="Hand"></Setter> 23 <Setter Property="Margin" Value="3"></Setter> 24 <Setter Property="MinWidth" Value="80"></Setter> 25 <Setter Property="MinHeight" Value="25"></Setter> 26 <Setter Property="BorderThickness" Value="0 0 0 0"></Setter> 27 </Style> 28 </ResourceDictionary> 29 </ResourceDictionary.MergedDictionaries> 30 </ResourceDictionary> 31 </UserControl.Resources> 32 <i:Interaction.Triggers> 33 <i:EventTrigger EventName="Loaded"> 34 <i:InvokeCommandAction Command="{Binding LoadedCommand}"></i:InvokeCommandAction> 35 </i:EventTrigger> 36 </i:Interaction.Triggers> 37 <Grid> 38 <Grid.RowDefinitions> 39 <RowDefinition Height="Auto"></RowDefinition> 40 <RowDefinition Height="Auto"></RowDefinition> 41 <RowDefinition Height="*"></RowDefinition> 42 <RowDefinition Height="Auto"></RowDefinition> 43 </Grid.RowDefinitions> 44 <TextBlock Text="Class information" FontSize="20" Background="AliceBlue" Margin="2"></TextBlock> 45 <StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Center"> 46 <TextBlock Text="specialized" VerticalAlignment="Center" Margin="2"></TextBlock> 47 <TextBox Margin="4" MinWidth="120" Height="30" 48 Text="{Binding Dept}" 49 HorizontalContentAlignment="Stretch" 50 mahApps:TextBoxHelper.ClearTextButton="True" 51 mahApps:TextBoxHelper.Watermark="specialized" 52 mahApps:TextBoxHelper.WatermarkAlignment="Left" 53 SpellCheck.IsEnabled="True" /> 54 <TextBlock Text="grade" VerticalAlignment="Center" Margin="2"></TextBlock> 55 <TextBox Margin="4" MinWidth="120" Height="30" 56 Text="{Binding Grade}" 57 HorizontalContentAlignment="Stretch" 58 mahApps:TextBoxHelper.ClearTextButton="True" 59 mahApps:TextBoxHelper.Watermark="grade" 60 mahApps:TextBoxHelper.WatermarkAlignment="Left" 61 SpellCheck.IsEnabled="True" /> 62 <Button Content="Inquire" Style="{DynamicResource MahApps.Styles.Button.Square.Accent}" Width="120" Height="30" Margin="3" Command="{Binding QueryCommand}"></Button> 63 <Button Content="new" Style="{DynamicResource MahApps.Styles.Button.Square.Accent}" Width="120" Height="30" Margin="3" Command="{Binding AddCommand}"></Button> 64 </StackPanel> 65 <DataGrid x:Name="dgClasses" 66 Grid.Row="2" 67 Grid.Column="0" 68 Margin="2" 69 AutoGenerateColumns="False" 70 CanUserAddRows="False" 71 CanUserDeleteRows="False" 72 ItemsSource="{Binding Classes}" 73 RowHeaderWidth="0"> 74 <DataGrid.Columns> 75 <DataGridTextColumn Binding="{Binding Dept}" Header="specialized" Width="*" /> 76 <DataGridTextColumn Binding="{Binding Grade}" Header="grade" Width="*"/> 77 <DataGridTextColumn Binding="{Binding Name}" Header="class" Width="*"/> 78 <DataGridTextColumn Binding="{Binding HeadTeacher}" Header="head teacher" Width="*"/> 79 <DataGridTextColumn Binding="{Binding MonitorName}" Header="monitor" Width="*" /> 80 <DataGridTemplateColumn Header="operate" Width="*"> 81 <DataGridTemplateColumn.CellTemplate> 82 <DataTemplate> 83 <StackPanel Orientation="Horizontal"> 84 <Button Content="Edit" Style="{StaticResource LinkButton}" Command="{Binding RelativeSource={RelativeSource AncestorType=DataGrid, Mode=FindAncestor}, Path=DataContext.EditCommand}" CommandParameter="{Binding Id}"> 85 <Button.Template> 86 <ControlTemplate TargetType="Button"> 87 <TextBlock TextDecorations="Underline" HorizontalAlignment="Center"> 88 <ContentPresenter /> 89 </TextBlock> 90 </ControlTemplate> 91 </Button.Template> 92 </Button> 93 <Button Content="Delete" Style="{StaticResource LinkButton}" Command="{Binding RelativeSource={RelativeSource AncestorType=DataGrid, Mode=FindAncestor}, Path=DataContext.DeleteCommand}" CommandParameter="{Binding Id}"> 94 <Button.Template> 95 <ControlTemplate TargetType="Button"> 96 <TextBlock TextDecorations="Underline" HorizontalAlignment="Center"> 97 <ContentPresenter /> 98 </TextBlock> 99 </ControlTemplate> 100 </Button.Template> 101 </Button> 102 </StackPanel> 103 </DataTemplate> 104 </DataGridTemplateColumn.CellTemplate> 105 </DataGridTemplateColumn> 106 </DataGrid.Columns> 107 </DataGrid> 108 <ctrls:PageControl Grid.Row="3" DataContext="{Binding}" ></ctrls:PageControl> 109 </Grid> 110 </UserControl>
Add edit page
The new functions and editing functions of the class share one page, and the knowledge points involved are as follows:
- In the newly edited ViewModel, the class entity is a property, so when data binding in the view control, you need to bring the property name, such as: Classes.Name.
- The monitor list has no corresponding students when adding a new class, and it can be empty. After the students are maintained, they can be selected from the student list.
- The monitor list is the Combox drop-down box, which is bound to the student entity list, but the client only needs to see the student's name, so the DataTemplate needs to be rewritten to display only the student's name.
Add a new class information view, the specific code is as follows:
1 <UserControl x:Class="SIMS.ClassesModule.Views.AddEditClasses" 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.ClassesModule.Views" 7 mc:Ignorable="d" 8 xmlns:i="http://schemas.microsoft.com/xaml/behaviors" 9 xmlns:mahApps ="http://metro.mahapps.com/winfx/xaml/controls" 10 xmlns:prism="http://prismlibrary.com/" 11 d:DesignHeight="400" d:DesignWidth="600"> 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 <RowDefinition></RowDefinition> 44 <RowDefinition></RowDefinition> 45 <RowDefinition></RowDefinition> 46 </Grid.RowDefinitions> 47 48 49 <TextBlock Text="specialized" Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" Margin="3"></TextBlock> 50 <TextBox Grid.Row="0" Grid.Column="2" MinWidth="120" Height="35" VerticalAlignment="Center" Margin="3" Text="{Binding Classes.Dept}"></TextBox> 51 <TextBlock Text="grade" Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" Margin="3"></TextBlock> 52 <TextBox Grid.Row="1" Grid.Column="2" MinWidth="120" Height="35" VerticalAlignment="Center" Margin="3" Text="{Binding Classes.Grade}"></TextBox> 53 <TextBlock Text="class" Grid.Row="2" Grid.Column="1" VerticalAlignment="Center" Margin="3"></TextBlock> 54 <TextBox Grid.Row="2" Grid.Column="2" MinWidth="120" Height="35" VerticalAlignment="Center" Margin="3" Text="{Binding Classes.Name}"></TextBox> 55 <TextBlock Text="head teacher" Grid.Row="3" Grid.Column="1" VerticalAlignment="Center" Margin="3"></TextBlock> 56 <TextBox Grid.Row="3" Grid.Column="2" MinWidth="120" Height="35" VerticalAlignment="Center" Margin="3" Text="{Binding Classes.HeadTeacher}"></TextBox> 57 <TextBlock Text="monitor" Grid.Row="4" Grid.Column="1" VerticalAlignment="Center" Margin="3"></TextBlock> 58 <ComboBox Grid.Row="4" Grid.Column="2" MinWidth="120" Height="35" ItemsSource="{Binding Monitors}" mahApps:TextBoxHelper.ClearTextButton="True" SelectedItem="{Binding Monitor}"> 59 <ComboBox.ItemTemplate> 60 <DataTemplate> 61 <TextBlock Text="{Binding Name}"></TextBlock> 62 </DataTemplate> 63 </ComboBox.ItemTemplate> 64 </ComboBox> 65 <StackPanel Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Center" Margin="3"> 66 <Button Content="Cancel" Margin="5" MinWidth="120" Height="35" Style="{DynamicResource MahApps.Styles.Button.Square.Accent}" Command="{Binding CancelCommand}"></Button> 67 <Button Content="save" Margin="5" MinWidth="120" Height="35" Style="{DynamicResource MahApps.Styles.Button.Square.Accent}" Command="{Binding SaveCommand}"></Button> 68 </StackPanel> 69 <TextBlock Grid.Row="6" Grid.Column="1" Grid.ColumnSpan="2" Text="Note: When adding a new class, the monitor can be empty. After maintaining the students, the monitor can be set." Foreground="Red"></TextBlock> 70 </Grid> 71 </UserControl>
3. Client ViewModel
The class management module, corresponding to the ViewModel and the view, is also divided into the query list ViewModel and the new edit ViewModel, as shown below:
The ClassesViewModel page code is divided into three parts:
- Properties and constructors, mainly used for data binding, such as query conditions, lists, etc. All properties are assigned using SetProperty.
- Command Command, such as query, add, edit, delete commands, etc. All commands can be defined as DelegateCommand type.
- The paging part is omitted here because the paging function code is similar.
The specific code of ClassesViewModel is as follows:
1 namespace SIMS.ClassesModule.ViewModels 2 { 3 public class ClassesViewModel :BindableBase 4 { 5 #region Properties and Constructors 6 7 /// <summary> 8 /// specialized 9 /// </summary> 10 private string dept; 11 12 public string Dept 13 { 14 get { return dept; } 15 set { SetProperty(ref dept , value); } 16 } 17 18 /// <summary> 19 /// grade 20 /// </summary> 21 private string grade; 22 23 public string Grade 24 { 25 get { return grade; } 26 set { SetProperty(ref grade , value); } 27 } 28 29 30 31 private ObservableCollection<ClassesInfo> classes; 32 33 public ObservableCollection<ClassesInfo> Classes 34 { 35 get { return classes; } 36 set { SetProperty(ref classes, value); } 37 } 38 39 private IDialogService dialogService; 40 41 public ClassesViewModel(IDialogService dialogService) 42 { 43 this.dialogService = dialogService; 44 this.pageNum = 1; 45 this.pageSize = 20; 46 } 47 48 private void InitInfo() 49 { 50 Classes = new ObservableCollection<ClassesInfo>(); 51 var pagedRequst = ClassesHttpUtil.GetClassess(this.Dept,this.Grade, this.pageNum, this.pageSize); 52 var entities = pagedRequst.items; 53 Classes.AddRange(entities.Select(r=>new ClassesInfo(r))); 54 // 55 this.TotalCount = pagedRequst.count; 56 this.TotalPage = ((int)Math.Ceiling(this.TotalCount * 1.0 / this.pageSize)); 57 } 58 59 #endregion 60 61 #region event 62 63 private DelegateCommand loadedCommand; 64 65 public DelegateCommand LoadedCommand 66 { 67 get 68 { 69 if (loadedCommand == null) 70 { 71 loadedCommand = new DelegateCommand(Loaded); 72 } 73 return loadedCommand; 74 } 75 } 76 77 private void Loaded() 78 { 79 InitInfo(); 80 } 81 82 private DelegateCommand queryCommand; 83 84 public DelegateCommand QueryCommand 85 { 86 get 87 { 88 if (queryCommand == null) 89 { 90 queryCommand = new DelegateCommand(Query); 91 } 92 return queryCommand; 93 } 94 } 95 96 private void Query() { 97 this.pageNum = 1; 98 this.InitInfo(); 99 } 100 101 /// <summary> 102 /// new command 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("addEditClasses",null, AddEditCallBack, "MetroDialogWindow"); 121 } 122 123 private void AddEditCallBack(IDialogResult dialogResult) { 124 if (dialogResult != null && dialogResult.Result == ButtonResult.OK) { 125 //refresh the list 126 this.pageNum = 1; 127 this.InitInfo(); 128 } 129 } 130 131 /// <summary> 132 /// edit command 133 /// </summary> 134 private DelegateCommand<object> editCommand; 135 136 public DelegateCommand<object> EditCommand 137 { 138 get 139 { 140 if (editCommand == null) 141 { 142 editCommand = new DelegateCommand<object>(Edit); 143 } 144 return editCommand; 145 } 146 } 147 148 private void Edit(object obj) 149 { 150 if (obj == null) { 151 return; 152 } 153 var Id = int.Parse(obj.ToString()); 154 var classes = this.Classes.FirstOrDefault(r => r.Id == Id); 155 if (classes == null) 156 { 157 MessageBox.Show("invalid class ID"); 158 return; 159 } 160 if (MessageBoxResult.Yes != MessageBox.Show("Are you sure to delete?", "Confirm", MessageBoxButton.YesNo)) 161 { 162 return; 163 } 164 IDialogParameters dialogParameters = new DialogParameters(); 165 dialogParameters.Add("classes",classes); 166 this.dialogService.ShowDialog("addEditClasses", dialogParameters, AddEditCallBack, "MetroDialogWindow"); 167 } 168 169 /// <summary> 170 /// edit command 171 /// </summary> 172 private DelegateCommand<object> deleteCommand; 173 174 public DelegateCommand<object> DeleteCommand 175 { 176 get 177 { 178 if (deleteCommand == null) 179 { 180 deleteCommand = new DelegateCommand<object>(Delete); 181 } 182 return deleteCommand; 183 } 184 } 185 186 private void Delete(object obj) 187 { 188 if (obj == null) 189 { 190 return; 191 } 192 var Id = int.Parse(obj.ToString()); 193 var classes = this.Classes.FirstOrDefault(r => r.Id == Id); 194 if (classes == null) 195 { 196 MessageBox.Show("invalid class ID"); 197 return; 198 } 199 bool flag = ClassesHttpUtil.DeleteClasses(Id); 200 if (flag) { 201 this.pageNum = 1; 202 this.InitInfo(); 203 } 204 } 205 206 #endregion 207 208 } 209 }
The AddEditClassesViewModel code is also divided into three parts:
- Properties and constructors, mainly used for data binding, such as page text boxes, drop-down selection boxes, etc.
- Command Command, mainly used to respond to events, such as save, cancel, etc.
- Dialog interface, because the new editor is presented in the form of a pop-up box, so according to the requirements of the Prism framework, the IDialogAware interface needs to be implemented.
The specific code of AddEditClassesViewModel is as follows:
1 namespace SIMS.ClassesModule.ViewModels 2 { 3 public class AddEditClassesViewModel : BindableBase, IDialogAware 4 { 5 #region Properties and Constructors 6 7 /// <summary> 8 /// class entity 9 /// </summary> 10 private ClassesInfo classes; 11 12 public ClassesInfo Classes 13 { 14 get { return classes; } 15 set { SetProperty(ref classes ,value); } 16 } 17 18 private List<StudentEntity> monitors; 19 20 public List<StudentEntity> Monitors 21 { 22 get { return monitors; } 23 set { SetProperty(ref monitors , value); } 24 } 25 26 private StudentEntity monitor; 27 28 public StudentEntity Monitor 29 { 30 get { return monitor; } 31 set { SetProperty(ref monitor, value); } 32 } 33 34 public AddEditClassesViewModel() { 35 36 } 37 38 #endregion 39 40 #region Command 41 42 private DelegateCommand loadedCommand; 43 44 public DelegateCommand LoadedCommand 45 { 46 get 47 { 48 if (loadedCommand == null) 49 { 50 loadedCommand = new DelegateCommand(Loaded); 51 } 52 return loadedCommand; 53 } 54 } 55 56 private void Loaded() 57 { 58 this.Monitors= new List<StudentEntity>(); 59 if (Classes?.Id>0) { 60 var pagedRequst = StudentHttpUtil.GetStudentsByClasses(Classes.Id); 61 var entities = pagedRequst.items; 62 Monitors.AddRange(entities); 63 //If there is a monitor, assign the monitor to the monitor 64 if (Classes.Monitor > 0) { 65 this.Monitor= this.Monitors?.FirstOrDefault(r=>r.Id==Classes.Monitor); 66 } 67 } 68 69 } 70 71 private DelegateCommand cancelCommand; 72 73 public DelegateCommand CancelCommand 74 { 75 get 76 { 77 if (cancelCommand == null) 78 { 79 cancelCommand = new DelegateCommand(Cancel); 80 } 81 return cancelCommand; 82 } 83 } 84 85 private void Cancel() 86 { 87 RequestClose?.Invoke((new DialogResult(ButtonResult.Cancel))); 88 } 89 90 private DelegateCommand saveCommand; 91 92 public DelegateCommand SaveCommand 93 { 94 get 95 { 96 if (saveCommand == null) 97 { 98 saveCommand = new DelegateCommand(Save); 99 } 100 return saveCommand; 101 } 102 } 103 104 private void Save() { 105 if (Classes != null) { 106 Classes.CreateTime = DateTime.Now; 107 Classes.LastEditTime = DateTime.Now; 108 if (Monitor != null) { 109 Classes.Monitor = Monitor.Id; 110 } 111 bool flag=false; 112 if (Classes.Id > 0) { 113 flag = ClassesHttpUtil.UpdateClasses(Classes); 114 } 115 else { 116 flag = ClassesHttpUtil.AddClasses(Classes); 117 } 118 if (flag) 119 { 120 RequestClose?.Invoke((new DialogResult(ButtonResult.OK))); 121 } 122 } 123 } 124 125 126 #endregion 127 128 #region dialog 129 130 public string Title => "Add or edit class information"; 131 132 public event Action<IDialogResult> RequestClose; 133 134 public bool CanCloseDialog() 135 { 136 return true; 137 } 138 139 public void OnDialogClosed() 140 { 141 142 } 143 144 public void OnDialogOpened(IDialogParameters parameters) 145 { 146 if (parameters != null && parameters.ContainsKey("classes")) 147 { 148 this.Classes = parameters.GetValue<ClassesInfo>("classes"); 149 } 150 else { 151 this.Classes = new ClassesInfo(); 152 } 153 } 154 155 #endregion 156 157 } 158 }
4. Sample screenshot
A screenshot of the class management example is shown below:
Â
student management
1. Interface access class StudentHttpUtil
The student data table structure and service interface have been introduced in the second article. If you have any questions, you can go to the reference. The interface access class is used to encapsulate the interface provided by the access server. As follows:
1 namespace SIMS.Utils.Http 2 { 3 /// <summary> 4 /// student class Http Access generic classes 5 /// </summary> 6 public class StudentHttpUtil:HttpUtil 7 { 8 /// <summary> 9 /// pass id Inquire about student information 10 /// </summary> 11 /// <param name="id"></param> 12 /// <returns></returns> 13 public static StudentEntity GetStudent(int id) 14 { 15 Dictionary<string, object> data = new Dictionary<string, object>(); 16 data["id"] = id; 17 var str = Get(UrlConfig.STUDENT_GETSTUDENT, data); 18 var student = StrToObject<StudentEntity>(str); 19 return student; 20 } 21 22 public static PagedRequest<StudentEntity> GetStudents(string no,string name, int pageNum, int pageSize) { 23 Dictionary<string, object> data = new Dictionary<string, object>(); 24 data["no"] = no; 25 data["name"] = name; 26 data["pageNum"] = pageNum; 27 data["pageSize"] = pageSize; 28 var str = Get(UrlConfig.STUDENT_GETSTUDENTS, data); 29 var students = StrToObject<PagedRequest<StudentEntity>>(str); 30 return students; 31 } 32 33 public static PagedRequest<StudentEntity> GetStudentsByClasses(int classId) 34 { 35 Dictionary<string, object> data = new Dictionary<string, object>(); 36 data["classId"] = classId; 37 var str = Get(UrlConfig.STUDENT_GETSTUDENTSBYCLASSES, data); 38 var students = StrToObject<PagedRequest<StudentEntity>>(str); 39 return students; 40 } 41 42 public static bool AddStudent(StudentEntity student) 43 { 44 var ret = Post<StudentEntity>(UrlConfig.STUDENT_ADDSTUDENT, student); 45 return int.Parse(ret) == 0; 46 } 47 48 public static bool UpdateStudent(StudentEntity student) 49 { 50 var ret = Put<StudentEntity>(UrlConfig.STUDENT_UPDATESTUDENT, student); 51 return int.Parse(ret) == 0; 52 } 53 54 public static bool DeleteStudent(int Id) 55 { 56 Dictionary<string, string> data = new Dictionary<string, string>(); 57 data["Id"] = Id.ToString(); 58 var ret = Delete(UrlConfig.STUDENT_DELETESTUDENT, data); 59 return int.Parse(ret) == 0; 60 } 61 } 62 }
2. Client page view
The client view page of the student management module is also divided into two: student list query, and a new page for editing student information.
Student List Inquiry Page
The design of knowledge points on the student information list page is similar to that of class management, with only one difference:
- In the database, gender is stored in bit type. In C#, the data type is bool, but it needs to be converted to male or female display in the list, so Converter needs to be used for conversion.
Student information query page, the specific code is as follows:
1 <UserControl x:Class="SIMS.StudentModule.Views.Student" 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.StudentModule.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 xmlns:ctrls ="clr-namespace:SIMS.Utils.Controls;assembly=SIMS.Utils" 11 xmlns:conv="clr-namespace:SIMS.Utils.Converter;assembly=SIMS.Utils" 12 mc:Ignorable="d" 13 prism:ViewModelLocator.AutoWireViewModel="True" 14 d:DesignHeight="450" d:DesignWidth="800"> 15 16 <UserControl.Resources> 17 <ResourceDictionary> 18 <ResourceDictionary.MergedDictionaries> 19 <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" /> 20 <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Blue.xaml" /> 21 <ResourceDictionary> 22 <conv:SexConverter x:Key="SexConverter"></conv:SexConverter> 23 <Style x:Key="LinkButton" TargetType="Button"> 24 <Setter Property="Background" Value="White"></Setter> 25 <Setter Property="Cursor" Value="Hand"></Setter> 26 <Setter Property="Margin" Value="3"></Setter> 27 <Setter Property="MinWidth" Value="80"></Setter> 28 <Setter Property="MinHeight" Value="25"></Setter> 29 <Setter Property="BorderThickness" Value="0 0 0 0"></Setter> 30 </Style> 31 </ResourceDictionary> 32 </ResourceDictionary.MergedDictionaries> 33 </ResourceDictionary> 34 </UserControl.Resources> 35 <i:Interaction.Triggers> 36 <i:EventTrigger EventName="Loaded"> 37 <i:InvokeCommandAction Command="{Binding LoadedCommand}"></i:InvokeCommandAction> 38 </i:EventTrigger> 39 </i:Interaction.Triggers> 40 <Grid> 41 <Grid.RowDefinitions> 42 <RowDefinition Height="Auto"></RowDefinition> 43 <RowDefinition Height="Auto"></RowDefinition> 44 <RowDefinition Height="*"></RowDefinition> 45 <RowDefinition Height="Auto"></RowDefinition> 46 </Grid.RowDefinitions> 47 <TextBlock Text="student information" FontSize="20" Background="AliceBlue" Margin="2"></TextBlock> 48 <StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Center"> 49 <TextBlock Text="student ID" VerticalAlignment="Center" Margin="2"></TextBlock> 50 <TextBox Margin="4" MinWidth="120" Height="30" 51 Text="{Binding No}" 52 HorizontalContentAlignment="Stretch" 53 mahApps:TextBoxHelper.ClearTextButton="True" 54 mahApps:TextBoxHelper.Watermark="student ID" 55 mahApps:TextBoxHelper.WatermarkAlignment="Left" 56 SpellCheck.IsEnabled="True" /> 57 <TextBlock Text="Name" VerticalAlignment="Center" Margin="2"></TextBlock> 58 <TextBox Margin="4" MinWidth="120" Height="30" 59 Text="{Binding Name}" 60 HorizontalContentAlignment="Stretch" 61 mahApps:TextBoxHelper.ClearTextButton="True" 62 mahApps:TextBoxHelper.Watermark="student name" 63 mahApps:TextBoxHelper.WatermarkAlignment="Left" 64 SpellCheck.IsEnabled="True" /> 65 <Button Content="Inquire" Style="{DynamicResource MahApps.Styles.Button.Square.Accent}" Width="120" Height="30" Margin="3" Command="{Binding QueryCommand}"></Button> 66 <Button Content="new" Style="{DynamicResource MahApps.Styles.Button.Square.Accent}" Width="120" Height="30" Margin="3" Command="{Binding AddCommand}"></Button> 67 </StackPanel> 68 <DataGrid x:Name="dgStudent" 69 Grid.Row="2" 70 Grid.Column="0" 71 Margin="2" 72 AutoGenerateColumns="False" 73 CanUserAddRows="False" 74 CanUserDeleteRows="False" 75 ItemsSource="{Binding Students}" 76 RowHeaderWidth="0"> 77 <DataGrid.Columns> 78 <DataGridTextColumn Binding="{Binding No}" Header="student ID" Width="*" /> 79 <DataGridTextColumn Binding="{Binding Name}" Header="Name" Width="*"/> 80 <DataGridTextColumn Binding="{Binding Age}" Header="age" Width="*"/> 81 <DataGridTextColumn Binding="{Binding Sex, Converter={StaticResource SexConverter}}" Header="gender" Width="*"/> 82 <DataGridTextColumn Binding="{Binding ClassesName}" Header="class" Width="*" /> 83 <DataGridTemplateColumn Header="operate" Width="*"> 84 <DataGridTemplateColumn.CellTemplate> 85 <DataTemplate> 86 <StackPanel Orientation="Horizontal"> 87 <Button Content="Edit" Style="{StaticResource LinkButton}" Command="{Binding RelativeSource={RelativeSource AncestorType=DataGrid, Mode=FindAncestor}, Path=DataContext.EditCommand}" CommandParameter="{Binding Id}" > 88 <Button.Template> 89 <ControlTemplate TargetType="Button"> 90 <TextBlock TextDecorations="Underline" HorizontalAlignment="Center"> 91 <ContentPresenter /> 92 </TextBlock> 93 </ControlTemplate> 94 </Button.Template> 95 </Button> 96 <Button Content="Delete" Style="{StaticResource LinkButton}" Command="{Binding RelativeSource={RelativeSource AncestorType=DataGrid, Mode=FindAncestor}, Path=DataContext.DeleteCommand}" CommandParameter="{Binding Id}"> 97 <Button.Template> 98 <ControlTemplate TargetType="Button"> 99 <TextBlock TextDecorations="Underline" HorizontalAlignment="Center"> 100 <ContentPresenter /> 101 </TextBlock> 102 </ControlTemplate> 103 </Button.Template> 104 </Button> 105 </StackPanel> 106 </DataTemplate> 107 </DataGridTemplateColumn.CellTemplate> 108 </DataGridTemplateColumn> 109 </DataGrid.Columns> 110 </DataGrid> 111 <ctrls:PageControl Grid.Row="3" DataContext="{Binding}" ></ctrls:PageControl> 112 </Grid> 113 </UserControl>
Add edit page
The knowledge points involved in the new edit page are similar to the new page in the class, with only one difference:
- The bool type in C# needs to be bound to two radio buttons to represent male and female, so it needs to be extended.
Add an edit page, the specific code is as follows:
1 <UserControl x:Class="SIMS.StudentModule.Views.AddEditStudent" 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.StudentModule.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="600"> 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 <RowDefinition></RowDefinition> 44 <RowDefinition></RowDefinition> 45 </Grid.RowDefinitions> 46 47 48 <TextBlock Text="student ID" Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" Margin="3"></TextBlock> 49 <TextBox Grid.Row="0" Grid.Column="2" MinWidth="120" Height="35" VerticalAlignment="Center" Margin="3" Text="{Binding Student.No}"></TextBox> 50 <TextBlock Text="Name" Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" Margin="3"></TextBlock> 51 <TextBox Grid.Row="1" Grid.Column="2" MinWidth="120" Height="35" VerticalAlignment="Center" Margin="3" Text="{Binding Student.Name}"></TextBox> 52 <TextBlock Text="age" Grid.Row="2" Grid.Column="1" VerticalAlignment="Center" Margin="3"></TextBlock> 53 <TextBox Grid.Row="2" Grid.Column="2" MinWidth="120" Height="35" VerticalAlignment="Center" Margin="3" Text="{Binding Student.Age}"></TextBox> 54 <TextBlock Text="gender" Grid.Row="3" Grid.Column="1" VerticalAlignment="Center" Margin="3"></TextBlock> 55 <StackPanel Grid.Row="3" Grid.Column="2" Orientation="Horizontal" > 56 <RadioButton Content="male" IsChecked="{Binding Student.IsBoy}"></RadioButton> 57 <RadioButton Content="Female" IsChecked="{Binding Student.IsGirl}"></RadioButton> 58 </StackPanel> 59 60 <TextBlock Text="class" Grid.Row="4" Grid.Column="1" VerticalAlignment="Center" Margin="3"></TextBlock> 61 <ComboBox Grid.Row="4" Grid.Column="2" MinWidth="120" Height="35" ItemsSource="{Binding Classess}" mahApps:TextBoxHelper.ClearTextButton="True" SelectedItem="{Binding Classes}"> 62 <ComboBox.ItemTemplate> 63 <DataTemplate> 64 <StackPanel Orientation="Horizontal"> 65 <TextBlock Text="{Binding Dept}"></TextBlock> 66 <TextBlock Text="{Binding Grade}"></TextBlock> 67 <TextBlock Text="{Binding Name}"></TextBlock> 68 </StackPanel> 69 </DataTemplate> 70 </ComboBox.ItemTemplate> 71 </ComboBox> 72 <StackPanel Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Center" Margin="3"> 73 <Button Content="Cancel" Margin="5" MinWidth="120" Height="35" Style="{DynamicResource MahApps.Styles.Button.Square.Accent}" Command="{Binding CancelCommand}" ></Button> 74 <Button Content="save" Margin="5" MinWidth="120" Height="35" Style="{DynamicResource MahApps.Styles.Button.Square.Accent}" Command="{Binding SaveCommand}"></Button> 75 </StackPanel> 76 </Grid> 77 </UserControl>
3. Client ViewModel
The student manages the client-side ViewModel, which corresponds to the page view and is also divided into two parts
The StudentViewModel code is divided into three parts:
- Properties and constructors, mainly used for data binding, such as query conditions, lists, etc. All properties are assigned using SetProperty.
- Command Command, such as query, add, edit, delete commands, etc. All commands can be defined as DelegateCommand type.
- The paging part is omitted here because the paging function code is similar.
The specific code of StudentViewModel is as follows:
1 namespace SIMS.StudentModule.ViewModels 2 { 3 public class StudentViewModel:BindableBase 4 { 5 #region Properties and Constructors 6 7 /// <summary> 8 /// student ID 9 /// </summary> 10 private string no; 11 12 public string No 13 { 14 get { return no; } 15 set { SetProperty(ref no , value); } 16 } 17 18 /// <summary> 19 /// student name 20 /// </summary> 21 private string name; 22 23 public string Name 24 { 25 get { return name; } 26 set { SetProperty(ref name, value); } 27 } 28 29 private ObservableCollection<StudentInfo> students; 30 31 public ObservableCollection<StudentInfo> Students 32 { 33 get { return students; } 34 set { SetProperty(ref students, value); } 35 } 36 37 private IDialogService dialogService; 38 39 public StudentViewModel(IDialogService dialogService) { 40 this.dialogService = dialogService; 41 this.pageNum = 1; 42 this.pageSize = 20; 43 } 44 45 private void InitInfo() { 46 Students = new ObservableCollection<StudentInfo>(); 47 var pagedRequst = StudentHttpUtil.GetStudents(this.No,this.Name, this.pageNum, this.pageSize); 48 var entities = pagedRequst.items; 49 Students.AddRange(entities.Select(r=>new StudentInfo(r))); 50 // 51 this.TotalCount = pagedRequst.count; 52 this.TotalPage=((int)Math.Ceiling(this.TotalCount*1.0/this.pageSize)); 53 } 54 55 #endregion 56 57 #region event 58 59 private DelegateCommand loadedCommand; 60 61 public DelegateCommand LoadedCommand 62 { 63 get 64 { 65 if (loadedCommand == null) 66 { 67 loadedCommand = new DelegateCommand(Loaded); 68 } 69 return loadedCommand; 70 } 71 } 72 73 private void Loaded() 74 { 75 InitInfo(); 76 } 77 78 /// <summary> 79 /// new command 80 /// </summary> 81 private DelegateCommand addCommand; 82 83 public DelegateCommand AddCommand 84 { 85 get 86 { 87 if (addCommand == null) 88 { 89 addCommand = new DelegateCommand(Add); 90 } 91 return addCommand; 92 } 93 } 94 95 private void Add() 96 { 97 this.dialogService.ShowDialog("addEditStudent", null, AddEditCallBack, "MetroDialogWindow"); 98 } 99 100 private void AddEditCallBack(IDialogResult dialogResult) 101 { 102 if (dialogResult != null && dialogResult.Result == ButtonResult.OK) 103 { 104 //refresh the list 105 this.pageNum = 1; 106 this.InitInfo(); 107 } 108 } 109 110 /// <summary> 111 /// edit command 112 /// </summary> 113 private DelegateCommand<object> editCommand; 114 115 public DelegateCommand<object> EditCommand 116 { 117 get 118 { 119 if (editCommand == null) 120 { 121 editCommand = new DelegateCommand<object>(Edit); 122 } 123 return editCommand; 124 } 125 } 126 127 private void Edit(object obj) { 128 if (obj == null) 129 { 130 return; 131 } 132 var Id = int.Parse(obj.ToString()); 133 var student = this.Students.FirstOrDefault(r => r.Id == Id); 134 if (student == null) 135 { 136 MessageBox.Show("invalid student ID"); 137 return; 138 } 139 if (MessageBoxResult.Yes != MessageBox.Show("Are you sure to delete?", "Confirm", MessageBoxButton.YesNo)) 140 { 141 return; 142 } 143 IDialogParameters dialogParameters = new DialogParameters(); 144 dialogParameters.Add("student", student); 145 this.dialogService.ShowDialog("addEditStudent", dialogParameters, AddEditCallBack, "MetroDialogWindow"); 146 } 147 148 /// <summary> 149 /// edit command 150 /// </summary> 151 private DelegateCommand<object> deleteCommand; 152 153 public DelegateCommand<object> DeleteCommand 154 { 155 get 156 { 157 if (deleteCommand == null) 158 { 159 deleteCommand = new DelegateCommand<object>(Delete); 160 } 161 return deleteCommand; 162 } 163 } 164 165 private void Delete(object obj) 166 { 167 if (obj == null) 168 { 169 return; 170 } 171 var Id = int.Parse(obj.ToString()); 172 var classes = this.Students.FirstOrDefault(r => r.Id == Id); 173 if (classes == null) 174 { 175 MessageBox.Show("invalid student ID"); 176 return; 177 } 178 bool flag = StudentHttpUtil.DeleteStudent(Id); 179 if (flag) 180 { 181 this.pageNum = 1; 182 this.InitInfo(); 183 } 184 } 185 186 #endregion 187 188 } 189 }
The AddEditStudentViewModel code is also divided into three parts:
- Properties and constructors, mainly used for data binding, such as page text boxes, drop-down selection boxes, etc.
- Command Command, mainly used to respond to events, such as save, cancel, etc.
- Dialog interface, because the new editor is presented in the form of a pop-up box, so according to the requirements of the Prism framework, the IDialogAware interface needs to be implemented. (The implementation of the interface code is similar and omitted here)
The specific code of AddEditStudentViewModel is as follows:
1 namespace SIMS.StudentModule.ViewModels 2 { 3 public class AddEditStudentViewModel : BindableBase, IDialogAware 4 { 5 6 /// <summary> 7 /// class entity 8 /// </summary> 9 private ClassesEntity classes; 10 11 public ClassesEntity Classes 12 { 13 get { return classes; } 14 set { SetProperty(ref classes, value); } 15 } 16 17 /// <summary> 18 /// class list 19 /// </summary> 20 private List<ClassesEntity> classess; 21 22 public List<ClassesEntity> Classess 23 { 24 get { return classess; } 25 set { SetProperty(ref classess, value); } 26 } 27 28 private StudentInfo student; 29 30 public StudentInfo Student 31 { 32 get { return student; } 33 set { student = value; } 34 } 35 36 public AddEditStudentViewModel() { 37 38 } 39 40 #region Command 41 42 private DelegateCommand loadedCommand; 43 44 public DelegateCommand LoadedCommand 45 { 46 get 47 { 48 if (loadedCommand == null) 49 { 50 loadedCommand = new DelegateCommand(Loaded); 51 } 52 return loadedCommand; 53 } 54 } 55 56 private void Loaded() 57 { 58 this.Classess = new List<ClassesEntity>(); 59 var pagedRequst = ClassesHttpUtil.GetClassess(null,null,1,0);//0 means all classes 60 var entities = pagedRequst.items; 61 Classess.AddRange(entities); 62 } 63 64 private DelegateCommand cancelCommand; 65 66 public DelegateCommand CancelCommand 67 { 68 get 69 { 70 if (cancelCommand == null) 71 { 72 cancelCommand = new DelegateCommand(Cancel); 73 } 74 return cancelCommand; 75 } 76 } 77 78 private void Cancel() { 79 RequestClose?.Invoke((new DialogResult(ButtonResult.Cancel))); 80 } 81 82 private DelegateCommand saveCommand; 83 84 public DelegateCommand SaveCommand 85 { 86 get 87 { 88 if (saveCommand == null) 89 { 90 saveCommand = new DelegateCommand(Save); 91 } 92 return saveCommand; 93 } 94 } 95 96 private void Save() 97 { 98 if (Student != null) 99 { 100 Student.CreateTime = DateTime.Now; 101 Student.LastEditTime = DateTime.Now; 102 bool flag = false; 103 if (Classes != null) { 104 Student.ClassesId = Classes.Id; 105 } 106 if (Student.Id > 0) 107 { 108 flag = StudentHttpUtil.UpdateStudent(Student); 109 } 110 else 111 { 112 flag = StudentHttpUtil.AddStudent(Student); 113 } 114 if (flag) 115 { 116 RequestClose?.Invoke((new DialogResult(ButtonResult.OK))); 117 } 118 } 119 } 120 121 #endregion 122 } 123 }
4. Sample screenshot
A screenshot of the student management example is shown below:
Summarize
Through the class management module, student management module of this article, and the course management module in the previous article, it is not difficult to find that the development of each module consists of a list DataGrid, a text box TextBox, a drop-down box Combox, and a radio button. RadioButton, Button Button, etc., although the functions are slightly different, but they are always the same. The development method is also similar, and the complex functions are accumulated by ordinary functions. This is also the gradual arrangement of this series of articles from shallow to deep. I hope to be able to attract others, not limited to a certain function, but to be able to draw inferences from one case, self-understanding, in order to achieve the ability of self-development.