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


最近通过WPF开发项目,为了对WPF知识点进行总结,所以利用业余时间,开发一个学生信息管理系统【Student Information Management System】。本文主要简述如何通过WPF+Prism+MAH+WebApi进行开发基于三层架构的桌面版应用程序,仅供学习分享使用,如有不足之处,还请指正。

涉及知识点

  • WPF:WPF(Windows Presentation Foundation)是(微软推出的)基于Windows的用户界面框架,提供了统一的编程模型,语言和框架,做到了分离界面设计人员与开发人员的工作;WPF提供了全新的多媒体交互用户图形界面。相比于WinForm传统开发,在WPF中,通过核心的MVVM设计思想,实现前后端的分离。
  • Prism:Prism是一个用于在 WPF、Xamarin Form、Uno 平台和 WinUI 中构建松散耦合、可维护和可测试的 XAML 应用程序框架。通过Prism,可以简化原生MVVM实现方式,并引入分模块设计思想。在Prism中,每一个功能,都可以设计成一个独立的模块,各个模块之间松耦合,可维护,可测试。框架中包括 MVVM、依赖注入、Command、Message Event、导航、弹窗等功能。在后续程序功能设计中,都会用到。
  • MAH:MahApps是一套基于WPF的界面组件,通过该组件,可以使用较小的开发成本实现一个相对很好的界面效果。作为后端开发,最头疼的就是如何设计美化页面,MAH可以让开发人员用最少的时间来开发Metro风格的页面。
  • WebApi:一般是指ASP.NET WebApi 用于快速开发基于REST风格的数据接口的框架。

Prism的模块化思想

在应用程序开发中,如果不采用模块化思想,那么各个页面混合在一起,看起杂乱无章,具体如下所示:

当我们引入模块化思想,那么各个模块的界限将变得清晰,如下所示:

在本文示例的学生信息管理系统中,就是采用模块思想,使项目的各个模块即相对完整,又相互独立。如下所示:

在开发中,引入模块化思想,通过Prism进行代码布局,如下所示:

MVVM思想

MVVM是Model-View-ViewModel(模型-视图-视图模型)的缩写形式,它通常被用于WPF或Silverlight开发。MVVM的根本思想就是界面和业务功能进行分离,View的职责就是负责如何显示数据及发送命令,ViewModel的功能就是如何提供数据和执行命令。各司其职,互不影响。我们可以通过下图来直观的理解MVVM模式:

在本示例中,所有开发都将遵循MVVM思想的设计模式进行开发,如下所示:

页面布局

在学生信息管理系统主界面,根据传统的布局方式,主要分为上(Header),中【左(Navigation),右(Main Content)】,下(Footer)四个部分,如下所示:

创建一个模块

一个模块是一个独立的WPF类库,在项目中,一个普通的类实现了IModule接口,就表示一个模块,以学生模块为例,如下所示:

 1 using Prism.Ioc;
 2 using Prism.Modularity;
 3 using SIMS.StudentModule.ViewModels;
 4 using SIMS.StudentModule.Views;
 5 using System;
 6 
 7 namespace SIMS.StudentModule
 8 {
 9     public class StudentModule : IModule
10     {
11         public void OnInitialized(IContainerProvider containerProvider)
12         {
13             
14         }
15 
16         public void RegisterTypes(IContainerRegistry containerRegistry)
17         {
18             containerRegistry.RegisterForNavigation(nameof(Student));
19         }
20     }
21 }

注意:在模块中,需要实现两个接口方法。在此模块中的RegisterTypes方法中,可以注册导航,窗口等以及初始化工作。

如果不注册为导航,而是需要注册到某一个Region中,则可以在OnInitialized方法中进行,以导航模块为例,如下所示:

 1 using Prism.Ioc;
 2 using Prism.Modularity;
 3 using Prism.Regions;
 4 using SIMS.NavigationModule.Views;
 5 using System;
 6 
 7 namespace SIMS.NavigationModule
 8 {
 9     public class NavigationModule : IModule
10     {
11         public void OnInitialized(IContainerProvider containerProvider)
12         {
13             var regionManager = containerProvider.Resolve();
14             regionManager.RegisterViewWithRegion("NavRegion",typeof(Navigation));
15         }
16 
17         public void RegisterTypes(IContainerRegistry containerRegistry)
18         {
19         }
20     }
21 }

View和ViewModel自动适配

View和ViewMode在注册导航时,可以手动匹配,也可以自动匹配【需要以固定的方式命名才可以自动适配】。自动适配,需要是在UserControl中,增加一句prism:ViewModelLocator.AutoWireViewModel="True"即可,以标题头为例,如下所示:

 1 <UserControl x:Class="SIMS.Views.Header"
 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.Views"
 7              mc:Ignorable="d"
 8              xmlns:prism="http://prismlibrary.com/"
 9              prism:ViewModelLocator.AutoWireViewModel="True"
10              xmlns:mahApps="http://metro.mahapps.com/winfx/xaml/controls"
11              d:DesignHeight="100" d:DesignWidth="800">
12     <UserControl.Resources>
13         <ResourceDictionary>
14             <ResourceDictionary.MergedDictionaries>
15                 <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Blue.xaml" />
16             ResourceDictionary.MergedDictionaries>
17         ResourceDictionary>
18     UserControl.Resources>
19 
20     <Grid Background="{DynamicResource MahApps.Brushes.Accent}">
21         <Grid.RowDefinitions>
22             <RowDefinition Height="*">RowDefinition>
23             <RowDefinition Height="Auto">RowDefinition>
24         Grid.RowDefinitions>
25         <TextBlock Grid.Row="0" Text="学生信息管理系统" Foreground="White" FontSize="32" FontWeight="Bold" HorizontalAlignment="Left" VerticalAlignment="Center"  Margin="20,5">TextBlock>
26         <StackPanel Grid.Row="1" HorizontalAlignment="Right" Orientation="Horizontal">
27             <TextBlock Text="Hello" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="3">TextBlock>
28             <TextBlock Text="Admin" Foreground="White"  Margin="3" FontWeight="Bold">TextBlock>
29             <TextBlock Text="|" Foreground="White"  Margin="3">TextBlock>
30             <TextBlock Text="Logout" Foreground="White"  Margin="3" FontWeight="Bold">TextBlock>
31         StackPanel>
32     Grid>
33 
34 UserControl>

弹出模态窗口

在Prism中,模块中的视图都是以UserControl的形式存在,那么如果需要弹出窗体页面,就需要在ViewModel中,实现IDialogAware接口,以Login登录窗口为例,如下所示:

  1 using Prism.Regions;
  2 using Prism.Services.Dialogs;
  3 using SIMS.Views;
  4 using System;
  5 using System.Collections.Generic;
  6 using System.Linq;
  7 using System.Text;
  8 using System.Threading.Tasks;
  9 using System.Windows;
 10 
 11 namespace SIMS.ViewModels
 12 {
 13     public class LoginViewModel : BindableBase, IDialogAware
 14     {
 15         private IRegionManager _regionManager;
 16         private IContainerExtension _container;
 17 
 18         private string userName;
 19 
 20         public string UserName
 21         {
 22             get { return userName; }
 23             set {SetProperty(ref userName , value); }
 24         }
 25 
 26         private string password;
 27 
 28         public string Password
 29         {
 30             get { return password; }
 31             set { SetProperty(ref  password , value); }
 32         }
 33 
 34 
 35         public LoginViewModel(IContainerExtension container,IRegionManager regionManager)
 36         {
 37             this._container = container;
 38             this._regionManager = regionManager;
 39         }
 40 
 41         private void InitInfo() {
 42             var footer = _container.Resolve
(); 43 IRegion footerRegion = _regionManager.Regions["LoginFooterRegion"]; 44 footerRegion.Add(footer); 45 } 46 47 #region 命令 48 49 private DelegateCommand loadedCommand; 50 51 public DelegateCommand LoadedCommand 52 { 53 get 54 { 55 if (loadedCommand == null) 56 { 57 loadedCommand = new DelegateCommand(Loaded); 58 } 59 return loadedCommand; 60 } 61 } 62 63 private void Loaded() 64 { 65 //InitInfo(); 66 } 67 68 private DelegateCommand loginCommand; 69 70 public DelegateCommand LoginCommand 71 { 72 get 73 { 74 if (loginCommand == null) 75 { 76 loginCommand = new DelegateCommand(Login); 77 } 78 return loginCommand; 79 } 80 } 81 82 private void Login() { 83 if (string.IsNullOrEmpty(UserName) || string.IsNullOrEmpty(Password)) { 84 MessageBox.Show("用户名或密码为空,请确认"); 85 return; 86 } 87 if (UserName == "admin" && Password == "abc123") 88 { 89 CloseWindow(); 90 } 91 else { 92 MessageBox.Show("用户名密码不正确,请确认"); 93 return; 94 } 95 } 96 97 private DelegateCommand cancelCommand; 98 99 public DelegateCommand CancelCommand 100 { 101 get 102 { 103 if (cancelCommand == null) 104 { 105 cancelCommand = new DelegateCommand(Cancel); 106 } 107 return cancelCommand; 108 } 109 } 110 111 private void Cancel() { 112 RequestClose?.Invoke(new DialogResult(ButtonResult.Cancel)); 113 } 114 115 #endregion 116 117 #region DialogAware接口 118 119 public string Title => "SIMS-Login"; 120 121 public event Action RequestClose; 122 123 /// 124 /// 成功时关闭窗口 125 /// 126 public void CloseWindow() { 127 RequestClose?.Invoke(new DialogResult(ButtonResult.OK)); 128 } 129 130 public bool CanCloseDialog() 131 { 132 return true; 133 } 134 135 public void OnDialogClosed() 136 { 137 //当关闭时 138 RequestClose?.Invoke(new DialogResult(ButtonResult.Cancel)); 139 } 140 141 public void OnDialogOpened(IDialogParameters parameters) 142 { 143 //传递解析参数 144 } 145 146 #endregion 147 } 148 }

实现了IDialogAware接口,表示以窗口的形态出现,在需要弹出窗口的地方进行调用即可。如下所示:

1 public MainWindowViewModel(IContainerExtension container, IRegionManager regionManager, IEventAggregator eventAggregator,IDialogService dialogService) { 
2     this._container = container;
3     this._regionManager = regionManager;
4     this.eventAggregator = eventAggregator;
5     this._dialogService = dialogService;
6     //弹出登录窗口
7     this._dialogService.ShowDialog("Login", null, LoginCallback, "MetroDialogWindow");
8     this.eventAggregator.GetEvent().Subscribe(Navigation);
9 }

注意:MetroDialogWindow是自定义个一个Metro风格的窗口,如果为空,则采用默认窗口风格。

模块间交互

按照模块化设计思想,虽然各个模块之间相互独立,但是难免为遇到模块之间进行交互的情况,所以Prism提供了事件聚合器,通过命令的发布和订阅来实现模块间的数据交互。以导航模块为例,当点击某一个导航时,发布一个命令,在主窗口订阅此事件,当收到事件时,将此导航对应的页面渲染到主页面区域中。步骤如下:

1. 定义一个事件

 1 using Prism.Events;
 2 using System;
 3 using System.Collections.Generic;
 4 using System.Linq;
 5 using System.Text;
 6 using System.Threading.Tasks;
 7 
 8 namespace SIMS.Utils.Events
 9 {
10     /// 
11     /// 导航事件
12     /// 
13     public class NavEvent : PubSubEvent<string>
14     {
15     }
16 }

2. 发布事件

用户点击导航菜单时,触发NavCommand,然后发布命令。

 1 private DelegateCommand<object> navCommand;
 2 
 3 public DelegateCommand<object> NavCommand
 4 {
 5     get
 6     {
 7         if (navCommand == null)
 8         {
 9 
10             navCommand = new DelegateCommand<object>(Navigation);
11         }
12         return navCommand;
13     }
14 }
15 
16 private void Navigation(object obj) {
17     var menuItem = (HamburgerMenuItem)obj;
18     if (menuItem != null) { 
19         var tag = menuItem.Tag;
20         if (tag!=null) { 
21             this.eventAggregator.GetEvent().Publish(tag.ToString());
22         }
23     }
24 }

3. 订阅命令

在主窗口,订阅命令,当收到命令时,再初始化模块信息,如下所示:

 1 namespace SIMS.ViewModels
 2 {
 3     public class MainWindowViewModel:BindableBase
 4     {
 5 
 6         private IEventAggregator eventAggregator;
 7         private IContainerExtension _container;
 8         private IRegionManager _regionManager;
 9         private IDialogService _dialogService;
10         public MainWindowViewModel(IContainerExtension container, IRegionManager regionManager, IEventAggregator eventAggregator,IDialogService dialogService) { 
11             this._container = container;
12             this._regionManager = regionManager;
13             this.eventAggregator = eventAggregator;
14             this._dialogService = dialogService;
15             //弹出登录窗口
16             this._dialogService.ShowDialog("Login", null, LoginCallback, "MetroDialogWindow");
17             this.eventAggregator.GetEvent().Subscribe(Navigation);
18         }
19 
20         private void LoginCallback(IDialogResult dialogResult) {
21             if (dialogResult.Result != ButtonResult.OK) {
22                 Application.Current.Shutdown();
23             }
24         }
25 
26         #region 事件和命令
27 
28         private DelegateCommand loadedCommand;
29 
30         public DelegateCommand LoadedCommand
31         {
32             get {
33                 if (loadedCommand == null) {
34                     loadedCommand = new DelegateCommand(Loaded);
35                 }
36                 return loadedCommand; }
37         }
38 
39         private void Loaded() {
40             InitInfo();
41         }
42 
43 
44         
45 
46         private void InitInfo() {
47             var header = _container.Resolve
(); 48 IRegion headerRegion = _regionManager.Regions["HeaderRegion"]; 49 headerRegion.Add(header); 50 // 51 var footer = _container.Resolve
(); 52 IRegion footerRegion = _regionManager.Regions["FooterRegion"]; 53 footerRegion.Add(footer); 54 55 var welcome = _container.Resolve(); 56 IRegion welcomeRegion = _regionManager.Regions["ContentRegion"]; 57 welcomeRegion.Add(welcome); 58 } 59 60 private void Navigation(string source) { 61 _regionManager.RequestNavigate("ContentRegion", source); 62 //MessageBox.Show(source); 63 } 64 65 #endregion 66 } 67 }

注意:一般情况下,只有在不同模块时,才使用事件聚合器进行事件的订阅和发布。如果是同一模块,则没有必要。

核心代码

模块的配置

各个模块之间相互独立,所以在主模块中进行加载时,需要先进行配置。模块加载的方式有很多种,本例采用App.config配置方式,如下所示:

 1 <?xml version="1.0" encoding="utf-8" ?>
 2 <configuration>
 3     <configSections>
 4         <section name="modules" type="Prism.Modularity.ModulesConfigurationSection, Prism.Wpf" />
 5     configSections>
 6     <startup>
 7     startup>
 8     <modules>
 9         <module assemblyFile="SIMS.NavigationModule.dll" moduleType="SIMS.NavigationModule.NavigationModule, SIMS.NavigationModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="NavigationModule" startupLoaded="True" />
10         <module assemblyFile="SIMS.ScoreModule.dll" moduleType="SIMS.ScoreModule.ScoreModule, SIMS.ScoreModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="ScoreModule" startupLoaded="True" />
11         <module assemblyFile="SIMS.StudentModule.dll" moduleType="SIMS.StudentModule.StudentModule, SIMS.StudentModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="StudentModule" startupLoaded="True" />
12         <module assemblyFile="SIMS.ClassesModule.dll" moduleType="SIMS.ClassesModule.ClassesModule, SIMS.ClassesModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="ClassesModule" startupLoaded="True" />
13         <module assemblyFile="SIMS.CourseModule.dll" moduleType="SIMS.CourseModule.CourseModule, SIMS.CourseModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="CourseModule" startupLoaded="True" />
14         <module assemblyFile="SIMS.SysManagementModule.dll" moduleType="SIMS.SysManagementModule.SysManagementModule, SIMS.SysManagementModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="SysManagementModule" startupLoaded="True" />
15     modules>
16 configuration>

启动入口App.xaml,可以用来配置资源字典等初始化操作,如下所示:

 1 <prism:PrismApplication x:Class="SIMS.App"
 2              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4              xmlns:local="clr-namespace:SIMS"
 5              xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
 6              xmlns:prism="http://prismlibrary.com/"
 7              >
 8     <Application.Resources>
 9         <ResourceDictionary>
10             <ResourceDictionary.MergedDictionaries>
11                 <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
12                 <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
13                 <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Blue.xaml" />
14                 <ResourceDictionary Source="/Icons/Icons.xaml">ResourceDictionary>
15             ResourceDictionary.MergedDictionaries>
16         ResourceDictionary>
17     Application.Resources>
18 prism:PrismApplication>

启动入口App.xaml.cs,应用程序需要继承PrismApplication基类,才是一个Prism应用程序。在此文件中初始化App.config中配置的模块。如下所示:

 1 namespace SIMS
 2 {
 3     /// 
 4     /// Interaction logic for App.xaml
 5     /// 
 6     public partial class App : PrismApplication
 7     {
 8         protected override Window CreateShell()
 9         {
10             return Container.Resolve();
11         }
12 
13         protected override void RegisterTypes(IContainerRegistry containerRegistry)
14         {
15             containerRegistry.RegisterDialog(nameof(Login));
16             containerRegistry.Register("MetroDialogWindow");
17         }
18 
19         protected override IModuleCatalog CreateModuleCatalog()
20         {
21             return new ConfigurationModuleCatalog();
22         }
23     }
24 }

主窗口MainWindow.xaml页面布局,如下所示:

 1 <mahApps:MetroWindow x:Class="SIMS.Views.MainWindow"
 2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 5         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 6         xmlns:local="clr-namespace:SIMS"
 7         mc:Ignorable="d"
 8         xmlns:prism="http://prismlibrary.com/"
 9         xmlns:mahApps="http://metro.mahapps.com/winfx/xaml/controls"
10         xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
11         prism:ViewModelLocator.AutoWireViewModel="True"
12         mahApps:Title="SIMS--Student Information Management System"
13         mahApps:TitleCharacterCasing="Normal"
14         d:DesignHeight="1080" d:DesignWidth="1920"            
15          WindowState="Maximized">
16     <Window.Resources>
17         <ResourceDictionary>
18             <ResourceDictionary.MergedDictionaries>
19                 <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Blue.xaml" />
20             ResourceDictionary.MergedDictionaries>
21         ResourceDictionary>
22     Window.Resources>
23 
24     <i:Interaction.Triggers>
25         <i:EventTrigger EventName="Loaded">
26             <i:InvokeCommandAction Command="{Binding LoadedCommand}">i:InvokeCommandAction>
27         i:EventTrigger>
28     i:Interaction.Triggers>
29     <Grid ShowGridLines="True">
30         <Grid.RowDefinitions>
31             <RowDefinition Height="Auto">RowDefinition>
32             <RowDefinition Height="*">RowDefinition>
33             <RowDefinition Height="Auto">RowDefinition>
34         Grid.RowDefinitions>
35         <Grid.ColumnDefinitions>
36             <ColumnDefinition Width="Auto">ColumnDefinition>
37             <ColumnDefinition Width="*">ColumnDefinition>
38         Grid.ColumnDefinitions>
39         <ContentControl prism:RegionManager.RegionName="HeaderRegion"  Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" MinHeight="80">ContentControl>
40         <ContentControl prism:RegionManager.RegionName="NavRegion" Grid.Row="1" Grid.Column="0">ContentControl>
41         <ContentControl prism:RegionManager.RegionName="ContentRegion" Grid.Row="1" Grid.Column="1">ContentControl>
42         <ContentControl prism:RegionManager.RegionName="FooterRegion" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" MinHeight="50">ContentControl>
43     Grid>
44 mahApps:MetroWindow>

主窗口MainWindowViewModel,代码如下:

 1 namespace SIMS.ViewModels
 2 {
 3     public class MainWindowViewModel:BindableBase
 4     {
 5 
 6         private IEventAggregator eventAggregator;
 7         private IContainerExtension _container;
 8         private IRegionManager _regionManager;
 9         private IDialogService _dialogService;
10         public MainWindowViewModel(IContainerExtension container, IRegionManager regionManager, IEventAggregator eventAggregator,IDialogService dialogService) { 
11             this._container = container;
12             this._regionManager = regionManager;
13             this.eventAggregator = eventAggregator;
14             this._dialogService = dialogService;
15             //弹出登录窗口
16             this._dialogService.ShowDialog("Login", null, LoginCallback, "MetroDialogWindow");
17             this.eventAggregator.GetEvent().Subscribe(Navigation);
18         }
19 
20         private void LoginCallback(IDialogResult dialogResult) {
21             if (dialogResult.Result != ButtonResult.OK) {
22                 Application.Current.Shutdown();
23             }
24         }
25 
26         #region 事件和命令
27 
28         private DelegateCommand loadedCommand;
29 
30         public DelegateCommand LoadedCommand
31         {
32             get {
33                 if (loadedCommand == null) {
34                     loadedCommand = new DelegateCommand(Loaded);
35                 }
36                 return loadedCommand; }
37         }
38 
39         private void Loaded() {
40             InitInfo();
41         }
42 
43 
44         
45 
46         private void InitInfo() {
47             var header = _container.Resolve
(); 48 IRegion headerRegion = _regionManager.Regions["HeaderRegion"]; 49 headerRegion.Add(header); 50 // 51 var footer = _container.Resolve
(); 52 IRegion footerRegion = _regionManager.Regions["FooterRegion"]; 53 footerRegion.Add(footer); 54 55 var welcome = _container.Resolve(); 56 IRegion welcomeRegion = _regionManager.Regions["ContentRegion"]; 57 welcomeRegion.Add(welcome); 58 } 59 60 private void Navigation(string source) { 61 _regionManager.RequestNavigate("ContentRegion", source); 62 //MessageBox.Show(source); 63 } 64 65 #endregion 66 } 67 }

导航页面Navigation.xaml页面采用MAH的Hamburger菜单,如下所示:

  1 <UserControl x:Class="SIMS.NavigationModule.Views.Navigation"
  2              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5              xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
  6              xmlns:local="clr-namespace:SIMS.NavigationModule.Views"
  7              xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
  8              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  9              xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
 10              xmlns:prism="http://prismlibrary.com/"
 11              prism:ViewModelLocator.AutoWireViewModel="True"
 12              d:DesignHeight="300"
 13              d:DesignWidth="240"
 14              mc:Ignorable="d">
 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/Fonts.xaml" />
 21                 <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Blue.xaml" />
 22             ResourceDictionary.MergedDictionaries>
 23             
 24             <DataTemplate x:Key="HamburgerMenuItem" DataType="{x:Type mah:HamburgerMenuGlyphItem}">
 25                 <DockPanel Height="48" LastChildFill="True">
 26                     <Grid x:Name="IconPart"
 27                           DockPanel.Dock="Left">
 28 
 29                         <Image Margin="12"
 30                                HorizontalAlignment="Center"
 31                                VerticalAlignment="Center"
 32                                Source="{Binding Glyph}" />
 33                     Grid>
 34                     <TextBlock x:Name="TextPart"
 35                                VerticalAlignment="Center"
 36                                FontSize="16"
 37                                Text="{Binding Label}" />
 38                 DockPanel>
 39             DataTemplate>
 40 
 41 
 42             <DataTemplate x:Key="HamburgerOptionsMenuItem" DataType="{x:Type mah:HamburgerMenuIconItem}">
 43                 <DockPanel Height="48" LastChildFill="True">
 44                     <ContentControl x:Name="IconPart"
 45                                     Content="{Binding Icon}"
 46                                     DockPanel.Dock="Left"
 47                                     Focusable="False"
 48                                     IsTabStop="False" />
 49                     <TextBlock x:Name="TextPart"
 50                                VerticalAlignment="Center"
 51                                FontSize="16"
 52                                Text="{Binding Label}" />
 53                 DockPanel>
 54             DataTemplate>
 55         ResourceDictionary>
 56     UserControl.Resources>
 57 
 58     <Grid Background="{DynamicResource MahApps.Brushes.Accent}">
 59         <Grid.ColumnDefinitions>
 60             <ColumnDefinition Width="Auto" />
 61         Grid.ColumnDefinitions>
 62         <mah:HamburgerMenu x:Name="HamburgerMenuControl" Grid.Column="0"
 63                                DisplayMode="CompactOverlay"
 64                                Margin="0"
 65                                IsPaneOpen="True"
 66                            
 67                                HamburgerButtonHelpText="Please click me"
 68                                HamburgerButtonClick="HamburgerMenuControl_HamburgerButtonClick"
 69                                ItemTemplate="{StaticResource HamburgerMenuItem}"
 70                                OptionsItemTemplate="{StaticResource HamburgerOptionsMenuItem}"
 71                                ItemsSource="{Binding NavItems}"
 72                                VerticalScrollBarOnLeftSide="False">
 73             <i:Interaction.Triggers>
 74                 <i:EventTrigger EventName="ItemInvoked">
 75                     <i:InvokeCommandAction Command="{Binding NavCommand}" CommandParameter="{Binding ElementName=HamburgerMenuControl, Path=SelectedItem}" >i:InvokeCommandAction>
 76                 i:EventTrigger>
 77             i:Interaction.Triggers>
 78             
 79             <mah:HamburgerMenu.HamburgerMenuHeaderTemplate>
 80                 <DataTemplate>
 81                     <TextBlock HorizontalAlignment="Center"
 82                                    VerticalAlignment="Center"
 83                                    FontSize="16"
 84                                    Foreground="White"
 85                                    Text="" />
 86                 DataTemplate>
 87             mah:HamburgerMenu.HamburgerMenuHeaderTemplate>
 88             <mah:HamburgerMenu.OptionsItemsSource>
 89                 <mah:HamburgerMenuItemCollection>
 90 
 91                     <mah:HamburgerMenuIconItem x:Name="AboutOption"
 92                                                    
 93                                                    Label="About">
 94                         <mah:HamburgerMenuIconItem.Icon>
 95                             <iconPacks:PackIconMaterial Width="22"
 96                                                             Height="22"
 97                                                             HorizontalAlignment="Center"
 98                                                             VerticalAlignment="Center"
 99                                                             Kind="Help" />
100                         mah:HamburgerMenuIconItem.Icon>
101                         <mah:HamburgerMenuIconItem.Tag>
102                             <TextBlock HorizontalAlignment="Center"
103                                            VerticalAlignment="Center"
104                                            FontSize="28"
105                                            FontWeight="Bold">
106                                     About
107                             TextBlock>
108                         mah:HamburgerMenuIconItem.Tag>
109                     mah:HamburgerMenuIconItem>
110 
111                 mah:HamburgerMenuItemCollection>
112             mah:HamburgerMenu.OptionsItemsSource>
113             
114             <mah:HamburgerMenu.ContentTemplate>
115                 <DataTemplate>
116                     <Grid x:Name="ContentGrid">
117                         <Grid.RowDefinitions>
118                             <RowDefinition Height="48" />
119                             <RowDefinition />
120                         Grid.RowDefinitions>
121                         <Border Grid.Row="0"
122                                     Margin="-1 0 -1 0"
123                                     Background="#7A7A7A">
124                             <TextBlock x:Name="Header"
125                                            HorizontalAlignment="Center"
126                                            VerticalAlignment="Center"
127                                            FontSize="24"
128                                            Foreground="White"
129                                            Text="{Binding Label}" />
130                         Border>
131                         <mah:TransitioningContentControl Grid.Row="1"
132                                                              Content="{Binding}"
133                                                              RestartTransitionOnContentChange="True"
134                                                              Transition="Default">
135                             <mah:TransitioningContentControl.Resources>
136                                 <DataTemplate DataType="{x:Type mah:HamburgerMenuGlyphItem}">
137                                     <Image Source="{Binding Glyph, Mode=OneWay, Converter={mah:NullToUnsetValueConverter}}" />
138                                 DataTemplate>
139                                 <DataTemplate DataType="{x:Type mah:HamburgerMenuIconItem}">
140                                     <ContentControl Content="{Binding Tag, Mode=OneWay}"
141                                                         Focusable="True"
142                                                         IsTabStop="False" />
143                                 DataTemplate>
144                             mah:TransitioningContentControl.Resources>
145                         mah:TransitioningContentControl>
146                     Grid>
147                 DataTemplate>
148             mah:HamburgerMenu.ContentTemplate>
149         mah:HamburgerMenu>
150 
151     Grid>
152 
153 UserControl>

导航页面NavigationViewModel页面代码,如下所示:

 1 namespace SIMS.NavigationModule.ViewModels
 2 {
 3     public class NavigationViewModel : BindableBase
 4     {
 5         #region 属性和构造函数
 6 
 7         private IEventAggregator eventAggregator;
 8 
 9         private List navItems;
10 
11         public List NavItems { get { return navItems; } set { SetProperty(ref navItems, value); } }
12 
13         public NavigationViewModel(IEventAggregator eventAggregator)
14         {
15             this.eventAggregator = eventAggregator;
16             navItems = new List();
17             navItems.Add(new HamburgerMenuHeaderItem() { Label = "学生管理"});
18             navItems.Add(new HamburgerMenuGlyphItem() { Label="学生管理",Tag="Student" ,Glyph="/images/icon_student.png"   });
19             navItems.Add(new HamburgerMenuGlyphItem() { Label = "班级管理",Tag="Classes"  ,  Glyph = "/images/icon_classes.png" });
20             navItems.Add(new HamburgerMenuGlyphItem() { Label = "课程管理", Tag="Course" , Glyph = "/images/icon_course.png" });
21             navItems.Add(new HamburgerMenuGlyphItem() { Label = "成绩管理" ,Tag="Score",  Glyph = "/images/icon_score.png" });
22             navItems.Add(new HamburgerMenuHeaderItem() { Label = "系统管理",  });
23             navItems.Add(new HamburgerMenuGlyphItem() { Label = "个人信息",Tag="Personal", Glyph = "/images/icon_personal.png" });
24             navItems.Add(new HamburgerMenuGlyphItem() { Label = "用户管理",Tag="User", Glyph = "/images/icon_user.png" });
25             navItems.Add(new HamburgerMenuGlyphItem() { Label = "角色管理",Tag="Role", Glyph = "/images/icon_role.png" });
26         }
27 
28         #endregion
29 
30         #region 命令
31 
32         private DelegateCommand<object> navCommand;
33 
34         public DelegateCommand<object> NavCommand
35         {
36             get
37             {
38                 if (navCommand == null)
39                 {
40 
41                     navCommand = new DelegateCommand<object>(Navigation);
42                 }
43                 return navCommand;
44             }
45         }
46 
47         private void Navigation(object obj) {
48             var menuItem = (HamburgerMenuItem)obj;
49             if (menuItem != null) { 
50                 var tag = menuItem.Tag;
51                 if (tag!=null) { 
52                     this.eventAggregator.GetEvent().Publish(tag.ToString());
53                 }
54             }
55         }
56 
57         #endregion
58     }
59 }

示例截图

本示例目前主要实现了登录,及主页面布局,导航等功能,如下所示:

备注

以上是本文介绍的关于学生信息管理系统的主要内容,旨在抛砖引玉一起学习,共同进步。

贺新郎·九日【作者】刘克庄 【朝代】宋

湛湛长空黑。更那堪、斜风细雨,乱愁如织。老眼平生空四海,赖有高楼百尺。看浩荡、千崖秋色。白发书生神州泪,尽凄凉、不向牛山滴。追往事,去无迹。
少年自负凌云笔。到而今、春华落尽,满怀萧瑟。常恨世人新意少,爱说南朝狂客。把破帽、年年拈出。若对黄花孤负酒,怕黄花、也笑人岑寂。鸿北去,日西匿。