• 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<Student, StudentViewModel>(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<IRegionManager>();
    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<Footer>();
     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<IDialogResult> RequestClose;
    122 
    123         /// <summary>
    124         /// 成功时关闭窗口
    125         /// </summary>
    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<NavEvent>().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     /// <summary>
    11     /// 导航事件
    12     /// </summary>
    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<NavEvent>().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<NavEvent>().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<Header>();
    48             IRegion headerRegion = _regionManager.Regions["HeaderRegion"];
    49             headerRegion.Add(header);
    50             //
    51             var footer = _container.Resolve<Footer>();
    52             IRegion footerRegion = _regionManager.Regions["FooterRegion"];
    53             footerRegion.Add(footer);
    54 
    55             var welcome = _container.Resolve<Welcome>();
    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>
    View Code

    启动入口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>
    View Code

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

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

    主窗口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>
    View Code

    主窗口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<NavEvent>().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<Header>();
    48             IRegion headerRegion = _regionManager.Regions["HeaderRegion"];
    49             headerRegion.Add(header);
    50             //
    51             var footer = _container.Resolve<Footer>();
    52             IRegion footerRegion = _regionManager.Regions["FooterRegion"];
    53             footerRegion.Add(footer);
    54 
    55             var welcome = _container.Resolve<Welcome>();
    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 }
    View Code

    导航页面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             <!--  This is the template for all menu items. In this sample we use the glyph items.  -->
     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             <!--  Header  -->
     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             <!--  Content  -->
    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>
    View Code

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

     1 namespace SIMS.NavigationModule.ViewModels
     2 {
     3     public class NavigationViewModel : BindableBase
     4     {
     5         #region 属性和构造函数
     6 
     7         private IEventAggregator eventAggregator;
     8 
     9         private List<HamburgerMenuItemBase> navItems;
    10 
    11         public List<HamburgerMenuItemBase> NavItems { get { return navItems; } set { SetProperty(ref navItems, value); } }
    12 
    13         public NavigationViewModel(IEventAggregator eventAggregator)
    14         {
    15             this.eventAggregator = eventAggregator;
    16             navItems = new List<HamburgerMenuItemBase>();
    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<NavEvent>().Publish(tag.ToString());
    53                 }
    54             }
    55         }
    56 
    57         #endregion
    58     }
    59 }
    View Code

    示例截图

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

    备注

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

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

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

  • 相关阅读:
    Netty指定分隔的字符
    Netty解决TCP粘包/拆包问题
    TCP粘包/拆包问题
    Netty5-应答服务器
    线程池中的线程的排序问题
    Java NIO 概述
    在windows中,如何使用cmd命令行窗口正确显示编码为utf-8格式的文字
    OXM
    Mysql event时间触发器,实现定时修改某些符合某一条件的某一字段
    linux 环境 tomcat 莫名奇妙挂掉
  • 原文地址:https://www.cnblogs.com/hsiang/p/16260662.html
Copyright © 2020-2023  润新知