• Wpf 使用 Prism 实战开发Day04


    一.菜单导航实现


    1.首先创建出所有的页面(View)及对应的页面逻辑处理类(ViewModel)

    1.  IndexView(首页)-----------------IndexViewModel
    2. ToDoView(待办事项)------------ToDoViewModel
    3. MemoView(忘备录)--------------MemoViewModel
    4. SettingsView(设置)--------------SettingsViewModel

    注意:创建View时,添加的是用户控件 

    2. 在 MainView.xaml 添加内容展示区域 

    通俗点理解就是,其他页面的内容需要有控件去展现出来给用户看。然后就用到一个ContentControl  控件来展现内容,并且也需要用到 Prism 框架里面的区域 (并且通过定义一个区域名称来定位到展现的位置)。我是这样理解的。首先这不是教程,是我学习的记录,如果错了,就错了。

    • 例如,在 ContentControl 中定义一个区域名称,并且使用 prism 注册这个区域
    <ContentControl prism:RegionManager.RegionName=""/>

     建议:通过一个扩展类来管理定义的一些属性名称

    例如:当前定义的区域名称,通过建立一个扩展类来进行管理

    1. public static class PrismManager
    2. {
    3. public static readonly string MainViewRegionName = "MainViewReion";
    4. }

    • 扩展类定义完成后,需要在使用到的 MainView 页面中,添加命名空间进行使用这个静态扩展类
    xmlns:ext="clr-namespace:MyToDo.Extensions"
    1. xmlns: 是引入命名空间固定的写法
    2. ext 是自定义的名称
    3. = 号后面是扩展类所在的命名空间 

    • 最后,在 ContentControl 控件中去引用这个静态类定义的属性
     <ContentControl prism:RegionManager.RegionName="{x:Static ext:PrismManager.MainViewRegionName}"/>

    x:Static 是引用静态类型的属性的固定前缀的写法 


     3.进行页面导航注册

    • 在App.xaml.cs中,把页面(View)和 业务处理类(ViewModel) 进行依赖关联并注册进导航容器中

    1. /// <summary>
    2. /// 依懒注入的方法
    3. /// summary>
    4. /// <param name="containerRegistry">param>
    5. protected override void RegisterTypes(IContainerRegistry containerRegistry)
    6. {
    7. containerRegistry.RegisterForNavigation();
    8. containerRegistry.RegisterForNavigation();
    9. containerRegistry.RegisterForNavigation();
    10. containerRegistry.RegisterForNavigation();
    11. }

     5. 接着在添加导航命令

    • 在MainViewModel.cs 中,添加导航命令。作用是用来驱动整个页面的导航
    • 接着,还需要添加 IRegionManager,通过在Prism 提供的IRegionManager.Regions 来找到应用程序所注册的导航区域名称(就是内容展现区域定义的名称)
    • 最后,通过.出来RequestNavigate 属性,取菜单传过来的命名空间做为导航的目标页面。
    1. public class MainViewModel: BindableBase
    2. {
    3. public MainViewModel(IRegionManager regionManager)
    4. {
    5. NavigateCommand = new DelegateCommand(Navigate);
    6. this.regionManager = regionManager;
    7. }
    8. ///
    9. /// 导航方法
    10. ///
    11. /// 菜单
    12. private void Navigate(MenuBar bar)
    13. {
    14. //命名空间为空,不进行导航
    15. if (bar == null || string.IsNullOrEmpty(bar.NameSpace)) return;
    16. regionManager.Regions[PrismManager.MainViewRegionName].RequestNavigate(bar.NameSpace);
    17. }
    18. ///
    19. /// 导航命令
    20. ///
    21. public DelegateCommand NavigateCommand { get; private set; }
    22. }

    6.实现上一步,下一步导航功能

    通过添加导航日志 IRegionNavigationJournal 来实现,上一步,下一步的导航功能

    • 修改导航方法,添加导航成功回调函数
    1. ///
    2. /// 导航方法
    3. ///
    4. /// 菜单
    5. private void Navigate(MenuBar bar)
    6. {
    7. //命名空间为空,不进行导航
    8. if (bar == null || string.IsNullOrEmpty(bar.NameSpace)) return;
    9. regionManager.Regions[PrismManager.MainViewRegionName].RequestNavigate(bar.NameSpace, back =>
    10. {
    11. });
    12. }
    • 添加一个区域导航日志 IRegionNavigationJournal,用来记录导航的结果 ,并且在回调函数中实例化导航日志
    1. public class MainViewModel: BindableBase
    2. {
    3. public MainViewModel(IRegionManager regionManager)
    4. {
    5. NavigateCommand = new DelegateCommand(Navigate);
    6. this.regionManager = regionManager;
    7. }
    8. ///
    9. /// 导航方法
    10. ///
    11. /// 菜单
    12. private void Navigate(MenuBar bar)
    13. {
    14. //命名空间为空,不进行导航
    15. if (bar == null || string.IsNullOrEmpty(bar.NameSpace)) return;
    16. regionManager.Regions[PrismManager.MainViewRegionName].RequestNavigate(bar.NameSpace, back =>
    17. {
    18. journal=back.Context.NavigationService.Journal;
    19. });
    20. }
    21. ///
    22. /// 导航命令
    23. ///
    24. public DelegateCommand NavigateCommand { get; private set; }
    25. private readonly IRegionManager regionManager;
    26. ///
    27. /// 导航日志
    28. ///
    29. private IRegionNavigationJournal journal;
    30. }
    • 接着,再添加两个命令,绑定前端按钮点击上一步或下一步按钮,并且进行初始化
    1. public class MainViewModel: BindableBase
    2. {
    3. public MainViewModel(IRegionManager regionManager)
    4. {
    5. NavigateCommand = new DelegateCommand(Navigate);
    6. this.regionManager = regionManager;
    7. GoBackCommand = new DelegateCommand(() =>
    8. {
    9. if(journal!=null && journal.CanGoBack) journal.GoBack();
    10. });
    11. GoForwardCommand = new DelegateCommand(() =>
    12. {
    13. if (journal != null && journal.CanGoForward) journal.GoForward();
    14. });
    15. }
    16. ///
    17. /// 导航方法
    18. ///
    19. /// 菜单
    20. private void Navigate(MenuBar bar)
    21. {
    22. //命名空间为空,不进行导航
    23. if (bar == null || string.IsNullOrEmpty(bar.NameSpace)) return;
    24. regionManager.Regions[PrismManager.MainViewRegionName].RequestNavigate(bar.NameSpace, back =>
    25. {
    26. journal=back.Context.NavigationService.Journal;
    27. });
    28. }
    29. ///
    30. /// 导航命令
    31. ///
    32. public DelegateCommand NavigateCommand { get; private set; }
    33. ///
    34. /// 下一步
    35. ///
    36. public DelegateCommand GoBackCommand { get; private set; }
    37. ///
    38. /// 上一步
    39. ///
    40. public DelegateCommand GoForwardCommand { get; private set; }
    41. private readonly IRegionManager regionManager;
    42. ///
    43. /// 导航日志
    44. ///
    45. private IRegionNavigationJournal journal;
    46. }
    • 最后,在MainView页面的上一步和下一步按钮绑定ViewMode 写好的命令

    7.在ListBox中,添加事件行为,作用是,当用户选中子项内容的时候,触发导航的行为。

    • 需要添加行为的命名空间

    引入行为命名空间 xmlns:i="http://schemas.microsoft.com/xaml/behaviors"

    •  接着在ListBox 中,添加选中行为事件,来触发导航

    1. <i:Interaction.Triggers>
    2. <i:EventTrigger EventName="SelectionChanged">
    3. <i:InvokeCommandAction Command="{Binding NavigateCommand}" CommandParameter="{Binding ElementName=menuBar,Path=SelectedItem}" />
    4. i:EventTrigger>
    5. i:Interaction.Triggers>
    •  Interaction.Triggers  行为触发器
    • EventTrigger 触发的事件
    • EventName 触发事件的名称,这个事件命名,一定是ListBox存在的事件名称,不是随便起的名称
    • InvokeCommandAction 绑定后台要触发的导航命令
    • CommandParameter 绑定当前选中项。例如。这是传过去后台命令的参数

    例如,上面是通过选中ListBox Item的子项来触发导航命令

    8.优化点击菜单子项的同时关闭左侧菜单

    • 只需要绑定ListBox 的SelectionChanged 选择事件,点击的时候让左侧边框收起即可

    1. //菜单选择事件
    2. menuBar.SelectionChanged += (s, e) =>
    3. {
    4. drawerHost.IsLeftDrawerOpen = false;
    5. };
    • menuBar  是ListBox 定义的名称
    • drawerHost 是左侧弹框定义的名称

    二.源码 

    • MainView.xaml 

    1. <Window x:Class="MyToDo.Views.MainView"
    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:ext="clr-namespace:MyToDo.Extensions"
    7. xmlns:local="clr-namespace:MyToDo"
    8. xmlns:prism="http://prismlibrary.com/"
    9. xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
    10. prism:ViewModelLocator.AutoWireViewModel="True"
    11. WindowStyle="None" WindowStartupLocation="CenterScreen" AllowsTransparency="True"
    12. Style="{StaticResource MaterialDesignWindow}"
    13. TextElement.Foreground="{DynamicResource MaterialDesignBody}"
    14. Background="{DynamicResource MaterialDesignPaper}"
    15. TextElement.FontWeight="Medium"
    16. TextElement.FontSize="14"
    17. FontFamily="{materialDesign:MaterialDesignFont}"
    18. mc:Ignorable="d"
    19. xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
    20. Title="MainWindow" Height="768" Width="1280">
    21. <materialDesign:DialogHost DialogTheme="Inherit"
    22. Identifier="RootDialog"
    23. SnackbarMessageQueue="{Binding ElementName=MainSnackbar, Path=MessageQueue}">
    24. <materialDesign:DrawerHost x:Name="drawerHost" IsLeftDrawerOpen="{Binding ElementName=MenuToggleButton, Path=IsChecked}">
    25. <materialDesign:DrawerHost.LeftDrawerContent>
    26. <DockPanel MinWidth="220" >
    27. <StackPanel DockPanel.Dock="Top" Margin="0,20">
    28. <Image Source="/Images/user.jpg" Width="50" Height="50">
    29. <Image.Clip>
    30. <EllipseGeometry Center="25,25" RadiusX="25" RadiusY="25" />
    31. Image.Clip>
    32. Image>
    33. <TextBlock Text="WPF gg" Margin="0,10" HorizontalAlignment="Center" />
    34. StackPanel>
    35. <ListBox x:Name="menuBar" ItemContainerStyle="{StaticResource MyListBoxItemStyle}" ItemsSource="{Binding MenuBars}">
    36. <i:Interaction.Triggers>
    37. <i:EventTrigger EventName="SelectionChanged">
    38. <i:InvokeCommandAction Command="{Binding NavigateCommand}" CommandParameter="{Binding ElementName=menuBar,Path=SelectedItem}" />
    39. i:EventTrigger>
    40. i:Interaction.Triggers>
    41. <ListBox.ItemTemplate>
    42. <DataTemplate>
    43. <StackPanel Orientation="Horizontal" Background="Transparent">
    44. <materialDesign:PackIcon Kind="{Binding Icon}" Margin="15,0" />
    45. <TextBlock Text="{Binding Title}" Margin="10,0"/>
    46. StackPanel>
    47. DataTemplate>
    48. ListBox.ItemTemplate>
    49. ListBox>
    50. DockPanel>
    51. materialDesign:DrawerHost.LeftDrawerContent>
    52. <DockPanel >
    53. <materialDesign:ColorZone Padding="16" x:Name="ColorZone"
    54. materialDesign:ElevationAssist.Elevation="Dp4"
    55. DockPanel.Dock="Top"
    56. Mode="PrimaryMid">
    57. <DockPanel LastChildFill="False">
    58. <StackPanel Orientation="Horizontal">
    59. <ToggleButton x:Name="MenuToggleButton"
    60. AutomationProperties.Name="HamburgerToggleButton"
    61. IsChecked="False"
    62. Style="{StaticResource MaterialDesignHamburgerToggleButton}" />
    63. <Button Margin="24,0,0,0"
    64. materialDesign:RippleAssist.Feedback="{Binding RelativeSource={RelativeSource Self}, Path=Foreground, Converter={StaticResource BrushRoundConverter}}"
    65. Command="{Binding GoForwardCommand}"
    66. Content="{materialDesign:PackIcon Kind=ArrowLeft,
    67. Size=24}"
    68. Foreground="{Binding RelativeSource={RelativeSource AncestorType={x:Type FrameworkElement}}, Path=(TextElement.Foreground)}"
    69. Style="{StaticResource MaterialDesignToolButton}"
    70. ToolTip="Previous Item" />
    71. <Button Margin="16,0,0,0"
    72. materialDesign:RippleAssist.Feedback="{Binding RelativeSource={RelativeSource Self}, Path=Foreground, Converter={StaticResource BrushRoundConverter}}"
    73. Command="{Binding GoBackCommand}"
    74. Content="{materialDesign:PackIcon Kind=ArrowRight,
    75. Size=24}"
    76. Foreground="{Binding RelativeSource={RelativeSource AncestorType={x:Type FrameworkElement}}, Path=(TextElement.Foreground)}"
    77. Style="{StaticResource MaterialDesignToolButton}"
    78. ToolTip="Next Item" />
    79. <TextBlock Margin="16,0,0,0"
    80. HorizontalAlignment="Center"
    81. VerticalAlignment="Center"
    82. AutomationProperties.Name="Material Design In XAML Toolkit"
    83. FontSize="22"
    84. Text="笔记本" />
    85. StackPanel>
    86. <StackPanel DockPanel.Dock="Right" Orientation="Horizontal">
    87. <Image Source="/Images/user.jpg" Width="25" Height="25">
    88. <Image.Clip>
    89. <EllipseGeometry Center="12.5,12.5" RadiusX="12.5" RadiusY="12.5" />
    90. Image.Clip>
    91. Image>
    92. <Button x:Name="btnMin" Style="{StaticResource MaterialDesignFlatMidBgButton}">
    93. <materialDesign:PackIcon Kind="MoveResizeVariant" />
    94. Button>
    95. <Button x:Name="btnMax" Style="{StaticResource MaterialDesignFlatMidBgButton}">
    96. <materialDesign:PackIcon Kind="CardMultipleOutline" />
    97. Button>
    98. <Button x:Name="btnClose" Style="{StaticResource MaterialDesignFlatMidBgButton}" Cursor="Hand">
    99. <materialDesign:PackIcon Kind="WindowClose" />
    100. Button>
    101. StackPanel>
    102. DockPanel>
    103. materialDesign:ColorZone>
    104. <ContentControl prism:RegionManager.RegionName="{x:Static ext:PrismManager.MainViewRegionName}"/>
    105. DockPanel>
    106. materialDesign:DrawerHost>
    107. materialDesign:DialogHost>
    108. Window>
    •  MainView.xaml.cs

    1. ///
    2. /// MainView.xaml 的交互逻辑
    3. ///
    4. public partial class MainView : Window
    5. {
    6. public MainView()
    7. {
    8. InitializeComponent();
    9. //最小化
    10. btnMin.Click += (s, e) =>
    11. {
    12. this.WindowState = WindowState.Minimized;//窗口设置最小
    13. };
    14. //最大化
    15. btnMax.Click += (s, e) =>
    16. {
    17. //判断窗口是否是最小化状态
    18. if (this.WindowState == WindowState.Maximized)
    19. {
    20. this.WindowState = WindowState.Normal; //改成正常状态
    21. }
    22. else
    23. {
    24. this.WindowState = WindowState.Maximized;//最大化
    25. }
    26. };
    27. //关闭
    28. btnClose.Click += (s, e) =>
    29. {
    30. this.Close();
    31. };
    32. //鼠标拖动事件
    33. ColorZone.MouseMove += (s, e) =>
    34. {
    35. //如果鼠标在拖动
    36. if (e.LeftButton == MouseButtonState.Pressed)
    37. {
    38. this.DragMove();//让窗口移动
    39. }
    40. };
    41. //导航栏双击事件
    42. ColorZone.MouseDoubleClick += (s, e) =>
    43. {
    44. //双击时,如果是窗口是正常形态,就变成最大化
    45. if (this.WindowState == WindowState.Normal)
    46. {
    47. this.WindowState = WindowState.Maximized;
    48. }
    49. else
    50. {
    51. this.WindowState = WindowState.Normal;//否则就变成正常的形态
    52. }
    53. };
    54. //菜单选择事件
    55. menuBar.SelectionChanged += (s, e) =>
    56. {
    57. drawerHost.IsLeftDrawerOpen = false;
    58. };
    59. }
    60. }
    • MainViewModel

    1. public class MainViewModel: BindableBase
    2. {
    3. public MainViewModel(IRegionManager regionManager)
    4. {
    5. MenuBars=new ObservableCollection();
    6. CreateMenuBar();
    7. NavigateCommand = new DelegateCommand(Navigate);
    8. this.regionManager = regionManager;
    9. GoBackCommand = new DelegateCommand(() =>
    10. {
    11. if(journal!=null && journal.CanGoBack) journal.GoBack();
    12. });
    13. GoForwardCommand = new DelegateCommand(() =>
    14. {
    15. if (journal != null && journal.CanGoForward) journal.GoForward();
    16. });
    17. }
    18. ///
    19. /// 导航方法
    20. ///
    21. /// 菜单
    22. private void Navigate(MenuBar bar)
    23. {
    24. //命名空间为空,不进行导航
    25. if (bar == null || string.IsNullOrEmpty(bar.NameSpace)) return;
    26. regionManager.Regions[PrismManager.MainViewRegionName].RequestNavigate(bar.NameSpace, back =>
    27. {
    28. journal=back.Context.NavigationService.Journal;
    29. });
    30. }
    31. ///
    32. /// 导航命令
    33. ///
    34. public DelegateCommand NavigateCommand { get; private set; }
    35. ///
    36. /// 下一步
    37. ///
    38. public DelegateCommand GoBackCommand { get; private set; }
    39. ///
    40. /// 上一步
    41. ///
    42. public DelegateCommand GoForwardCommand { get; private set; }
    43. private ObservableCollection menuBars;
    44. private readonly IRegionManager regionManager;
    45. ///
    46. /// 导航日志
    47. ///
    48. private IRegionNavigationJournal journal;
    49. public ObservableCollection MenuBars
    50. {
    51. get { return menuBars; }
    52. set { menuBars = value; RaisePropertyChanged(); }
    53. }
    54. void CreateMenuBar()
    55. {
    56. MenuBars.Add(new MenuBar() { Icon="Home",Title="首页",NameSpace="IndexView"});
    57. MenuBars.Add(new MenuBar() { Icon = "NotebookCheckOutline", Title = "待办事项", NameSpace = "ToDoView" });
    58. MenuBars.Add(new MenuBar() { Icon = "NotebookPlusOutline", Title = "忘备录", NameSpace = "MemoView" });
    59. MenuBars.Add(new MenuBar() { Icon = "Cog", Title = "设置", NameSpace = "SettingsView" });
    60. }
    61. }
    • App.xaml.cs
    1. public partial class App : PrismApplication
    2. {
    3. ///
    4. /// 创建启动页面
    5. ///
    6. ///
    7. protected override Window CreateShell()
    8. {
    9. return Container.Resolve();
    10. }
    11. ///
    12. /// 依懒注入的方法
    13. ///
    14. ///
    15. protected override void RegisterTypes(IContainerRegistry containerRegistry)
    16. {
    17. containerRegistry.RegisterForNavigation();
    18. containerRegistry.RegisterForNavigation();
    19. containerRegistry.RegisterForNavigation();
    20. containerRegistry.RegisterForNavigation();
    21. }
    22. }

  • 相关阅读:
    2022下半年(软考中级)系统集成项目管理工程师备考开班啦!
    ubuntu 修改nginx端口
    ShardingSphere-JDBC-简介-1
    应用系统集成-企业集成模式(EIP)
    《MySQL技术内幕:InnoDB存储引擎》学习笔记-第一章
    什么是REACH测试?
    图数据库 之 Neo4j - 应用场景3 - 知识图谱(8)
    Linux 运维工程师面试真题-3-Linux 磁盘及软件管理操作
    企业应用系统 PHP项目支持管理系统Dreamweaver开发mysql数据库web结构php编程计算机网页
    系列七、栈 & 堆
  • 原文地址:https://blog.csdn.net/weixin_39237340/article/details/134211880