Prism for WPF 搭建一个简单的模块化开发框架(一)

本文介绍了一个基于WPF的模块化应用程序框架的搭建过程,利用Prism框架和MEF实现了松耦合的模块化设计,详细解释了如何配置Bootstrapper以加载不同模块,并通过实例展示了各个组件的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

源码上传到这里了

https://gitee.com/shi2015/PW

https://github.com/756929019/PW

 

最近闲来无事又想搞搞WPF。。。。。
做个框架吧,可能又是半途而废。。。。总是坚持不下来

不废话了,

先看一下工程结构

布局大概是这样的

SystemHeader
AsideMain
Footer

 

PW.SystemHeader是用来放导航条,Log或者系统名称的

PW.Aside是准备放每个模块的树形菜单的,可以根据后续系统的需要做相应的变动和扩展

PW.Login就是一个登陆的模块了

PW.Footer只是一个底部的占位栏,需要的话可以放置一些显示信息

Main初始化时存放了Login的region 此时SystemHeader、Aside、Footer还未加载,所以主界面就算一个登陆页面

在登陆之后LoadModule,对应的区域也就加载上对用的模块了
主窗体布局代码是这样的

<Window x:Class="PW.Desktop.Shell"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
    xmlns:local="clr-namespace:PW.Desktop"	
        xmlns:prism="http://www.codeplex.com/prism"
	x:Name="Window"
	Title="Desktop"
    WindowStartupLocation="CenterScreen"
	UseLayoutRounding="True"
	Width="1024" Height="768" WindowState="Maximized" Loaded="Window_Loaded" WindowStyle="None" ResizeMode="NoResize">
    <Window.Background>
        <ImageBrush ImageSource="Images/bg/ocean.jpg"/>
    </Window.Background>
    <Grid x:Name="window">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid Height="30" Background="{DynamicResource ModuleControl.Panel.BackgroundBrush}" MouseLeftButtonDown="Grid_MouseLeftButtonDown" Cursor="Hand">
            <StackPanel  VerticalAlignment="Center" Orientation="Horizontal" FlowDirection="RightToLeft">
                <Button Width="25" Height="25" Content="X"  x:Name="closeBtn" Click="closeBtn_Click"></Button>
                <Button Width="25" Height="25" Content="口" x:Name="maxBtn" Click="maxBtn_Click"></Button>         
                <Button Width="25" Height="25" Content="-" x:Name="minBtn" Click="minBtn_Click"></Button>
            </StackPanel>
        </Grid>
        <Grid x:Name="LayoutRoot" Grid.Row="1">
               
    	<Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
    	</Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid Grid.Row="0" Grid.Column="0" x:Name="gridHeader" Grid.ColumnSpan="2" Margin="0">
            <ContentControl x:Name="headerContentControl" prism:RegionManager.RegionName="HeaderRegion" Margin="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"></ContentControl>
        </Grid>
        <Grid Grid.Row="1" Grid.Column="0" x:Name="gridAside" Margin="0">
            <ContentControl x:Name="asideContentControl" prism:RegionManager.RegionName="AsideRegion" Margin="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"></ContentControl>
        </Grid>
        <Grid  Grid.Row="1" Grid.Column="1" x:Name="gridMain" Margin="0">
            <ContentControl x:Name="mainContentControl" prism:RegionManager.RegionName="MainRegion" Margin="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"></ContentControl>
        </Grid>
        <Grid  Grid.Row="3" Grid.Column="0" x:Name="gridFooter"  Grid.ColumnSpan="2" Margin="0">
                <ContentControl x:Name="footerContentControl" prism:RegionManager.RegionName="FooterRegion" Margin="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"></ContentControl>
        </Grid>
    </Grid>
    </Grid>
</Window>

那么到底是怎么实现模块化松耦合呢,先贴一下代码

Bootstrapper.cs

// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.

namespace PW.Desktop
{
    using System.ComponentModel.Composition;
    using System.ComponentModel.Composition.Hosting;
    using System.Windows;
    using Prism.Logging;
    using Prism.Modularity;
    using Prism.Mef;

    /// <summary>
    /// Initializes Prism to start this quickstart Prism application to use Managed Extensibility Framework (MEF).
    /// </summary>
    public class Bootstrapper : MefBootstrapper
    {
        private readonly CallbackLogger callbackLogger = new CallbackLogger();

        /// <summary>
        /// Creates the shell or main window of the application.
        /// </summary>
        /// <returns>The shell of the application.</returns>
        /// <remarks>
        /// If the returned instance is a <see cref="DependencyObject"/>, the
        /// <see cref="MefBootstrapper"/> will attach the default <seealso cref="Microsoft.Practices.Composite.Regions.IRegionManager"/> of
        /// the application in its <see cref="Microsoft.Practices.Composite.Presentation.Regions.RegionManager.RegionManagerProperty"/> attached property
        /// in order to be able to add regions by using the <seealso cref=""Microsoft.Practices.Composite.Presentation.Regions.RegionManager.RegionNameProperty"/>
        /// attached property from XAML.
        /// </remarks>
        protected override DependencyObject CreateShell()
        {
            return this.Container.GetExportedValue<Shell>();
        }

        /// <summary>
        /// Initializes the shell.
        /// </summary>
        /// <remarks>
        /// The base implemention ensures the shell is composed in the container.
        /// </remarks>
        protected override void InitializeShell()
        {
            base.InitializeShell();

            Application.Current.MainWindow = (Shell) this.Shell;
            Application.Current.MainWindow.Show();
        }

        /// <summary>
        /// Configures the <see cref="AggregateCatalog"/> used by MEF.
        /// </summary>
        /// <remarks>
        /// The base implementation does nothing.
        /// </remarks>
        protected override void ConfigureAggregateCatalog()
        {
            base.ConfigureAggregateCatalog();

            // Add this assembly to export ModuleTracker
            this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(Bootstrapper).Assembly));

            // Module A is referenced in in the project and directly in code.
            this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(PW.LogIn.LoginModule).Assembly));

            // Module B and Module D are copied to a directory as part of a post-build step.
            // These modules are not referenced in the project and are discovered by inspecting a directory.
            // Both projects have a post-build step to copy themselves into that directory.
            DirectoryCatalog catalog = new DirectoryCatalog("DirectoryModules");
            this.AggregateCatalog.Catalogs.Add(catalog);
        }

        /// <summary>
        /// Configures the <see cref="CompositionContainer"/>.
        /// May be overwritten in a derived class to add specific type mappings required by the application.
        /// </summary>
        /// <remarks>
        /// The base implementation registers all the types direct instantiated by the bootstrapper with the container.
        /// The base implementation also sets the ServiceLocator provider singleton.
        /// </remarks>
        protected override void ConfigureContainer()
        {
            base.ConfigureContainer();

            // Because we created the CallbackLogger and it needs to be used immediately, we compose it to satisfy any imports it has.
            this.Container.ComposeExportedValue<CallbackLogger>(this.callbackLogger);
        }

        /// <summary>
        /// Creates the <see cref="IModuleCatalog"/> used by Prism.
        /// </summary>
        /// <remarks>
        /// The base implementation returns a new ModuleCatalog.
        /// </remarks>
        /// <returns>
        /// A ConfigurationModuleCatalog.
        /// </returns>
        protected override IModuleCatalog CreateModuleCatalog()
        {
            // When using MEF, the existing Prism ModuleCatalog is still the place to configure modules via configuration files.
            return new ConfigurationModuleCatalog();
        }

        /// <summary>
        /// Create the <see cref="ILoggerFacade"/> used by the bootstrapper.
        /// </summary>
        /// <remarks>
        /// The base implementation returns a new TextLogger.
        /// </remarks>
        /// <returns>
        /// A CallbackLogger.
        /// </returns>
        protected override ILoggerFacade CreateLogger()
        {
            // Because the Shell is displayed after most of the interesting boostrapper work has been performed,
            // this quickstart uses a special logger class to hold on to early log entries and display them 
            // after the UI is visible.
            return this.callbackLogger;
        }
    }
}

这里可以看到,基本上就算copy了Prism的demo代码,只是略微改动了一下ConfigureAggregateCatalog方法

手动加载了LogIn模块,这里工程里需要引入Login模块,然后剩余的所有布局模块以及系统模块都是在DirectoryModules下面
程序生成目录下面是这样的

这样的好处就算,各模块互不相干,以后可以像插件一样做一个新的模块放到DirectoryModules就能运行

然后每个模块下面只要做一个module的接口实现类类似AsideModule.cs这样

using Prism.Modularity;
using Prism.Mef.Modularity;
using Prism.Regions;
using System.ComponentModel.Composition;
using System;
using PW.Infrastructure;

namespace PW.Aside
{
    [ModuleExport(typeof(AsideModule), InitializationMode = InitializationMode.OnDemand)]
    public class AsideModule : IModule
    {
        private readonly IModuleTracker moduleTracker;
        private readonly IRegionManager regionManager;

        /// <summary>
        /// Initializes a new instance of the <see cref="ModuleB"/> class.
        /// </summary>
        /// <param name="moduleTracker">The module tracker.</param>
        [ImportingConstructor]
        public AsideModule(IModuleTracker moduleTracker, IRegionManager regionManager)
        {
            if (moduleTracker == null)
            {
                throw new ArgumentNullException("moduleTracker");
            }

            this.moduleTracker = moduleTracker;
            this.moduleTracker.RecordModuleConstructed(ModuleNames.Aside);
            this.regionManager = regionManager;
        }


        /// <summary>
        /// Notifies the module that it has be initialized.
        /// </summary>
        public void Initialize()
        {
            this.moduleTracker.RecordModuleInitialized(ModuleNames.Aside);
            regionManager.RegisterViewWithRegion(RegionNames.Aside, typeof(MenuView));
        }
    }
}

每个模块的基本上都一样,只是在Initialize中去为当前Region注册不同的view
好像也没什么好写的了,差不多就这样吧

说一下我遇到的坑和怎么解决的吧

就说布局中的MainRegion,因为初始化拿它加载了login模块,但是在登陆成功后想去加载Map或者SystemSet时,本来想的是用RegionManager更改mainContentControl的Region名称,但是死活不行,各种报错,有一种方法是能做到去加载不同的Region的,就是用ItemsControl,但是用ItemsControl效果很不好,不是全屏显示在MainRegion里

然后查资料,问csdn,都没有结构,可能是现在用wpf的本来就少吧,

最后没事儿时偶然就想到了,在不同的模块能有自己独立的Region做导航,MainRegion只是导航到各模块的主页面,就这样解决了

下面是做到现在的截图

这个本来是打算做一个登陆后的主导航的,上边和左边是要去掉的,还没处理,这时候布局其实已经出来了

再来几个换个风格的,其实就是换个背景图

写的比较乱,想用到项目里,就不上源码了,框架样式都还需要调整,对wpf不熟悉,也是写到哪查到哪,各种不会

现在准备给各模块做公用样式呢,又不知道怎么弄好了,,,,我多想有一个wpf的前辈给指教指教啊。。。。看到的朋友知道怎么弄可以给说一下啊,有好的方法,好的建议都能写下来啊,,,,感觉自己实在是有点瞎弄啊

<think>好的,我现在需要帮助用户了解如何使用Prism框架WPF搭建项目。用户已经提供了些相关的引用内容,包括项目创建、代码示例、核心思想以及模块加载的方法。首先,我需要整理这些信息,按照用户的要求结构清晰地分步骤说明。 首先,用户需要教程或示例代码,所以应该从创建项目开始。引用[1]提到通过Prism项目模板创建项目,支持WPF的.NET Framework和.NET Core。我应该建议用户安装Prism Template Pack扩展,这样他们可以直接在Visual Studio中使用模板,简化项目创建过程。这部分需要详细步骤,比如打开VS,搜索模板,选择类型等。 接下来是项目结构分析。Prism框架的核心在于模块化,所以需要解释App.xaml和App.xaml.cs的变化,特别是继承PrismApplication类,这是引用[2]和[3]提到的内容。要说明RegisterTypes和CreateShell方法的作用,用户提供的代码示例正好可以用在这里。需要确保用户理解如何注册依赖项和指定主窗口。 然后是模块化开发,引用[4]提到了手动加载模块和IModuleManager的使用。这里应该分步骤说明创建模块、注册视图、加载模块的过程。可能需要示例代码展示如何定义模块类,并在主窗口中加载模块,如按钮点击事件触发加载。 视图模型定位也是Prism的重要部分,引用[4]提到使用ViewModelLocationProvider。需要解释如何自动关联View和ViewModel,以及手动绑定的方法,确保用户理解两种方式的适用场景。 最后是导航和通信机制,这部分虽然用户提供的引用没有直接提到,但根据Prism的核心功能,应该简要说明区域管理和事件聚合器,让用户知道后续学习的方向。 在整理过程中,需要注意用户强调的系统级指令:行内公式用$...$,独立公式用$$...$$,但当前问题不涉及数学公式,所以可能不需要处理这点。另外,需要生成相关问题,根据用户提供的示例,问题应围绕Prism框架的深入使用,比如模块化优势、依赖注入、导航实现等。 需要检查所有引用的使用是否正确,比如引用[1]到[4]是否在适当的位置插入标注,确保回答真实可靠。同时,保持回答结构清晰,分步骤说明,代码示例用正确的格式,并符合中文回答的要求。 可能遇到的问题:用户是否已经安装了必要的工具,比如Visual Studio和Prism模板?如果用户环境没有配置好,可能需要额外步骤,但根据引用内容,用户已经提供了创建项目的方法,所以假设用户已经具备条件。此外,模块化开发部分可能需要更详细的解释,但用户提供的引用[4]中的代码示例足够说明加载模块的方法,所以可以引用该部分。 总结回答的结构应该是:创建项目、配置启动类、模块化开发、视图模型定位、导航与通信,然后相关问题。每个部分结合引用内容,确保信息准确,并在末尾添加引用标识。</think>以下是使用Prism框架构建WPF项目的分步教程及示例代码: ### 、创建Prism项目 1. 安装**Prism Template Pack**扩展(Visual Studio扩展),通过模板快速创建项目[^1] 2. 在Visual Studio中选择: *文件 → 新建 → 项目 → 搜索"Prism" → 选择"Prism Blank App (WPF)"* 支持.NET Framework和.NET Core版本选择 ### 二、配置启动类 修改`App.xaml.cs`继承`PrismApplication`基类[^3]: ```csharp public partial class App : PrismApplication { // 注册依赖项 protected override void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterSingleton<IMyService, MyService>(); // [^2] } // 创建主窗口 protected override Window CreateShell() { return Container.Resolve<MainWindow>(); // } } ``` ### 三、模块化开发 1. 创建模块项目(Class Library) 2. 实现`IModule`接口: ```csharp public class ModuleAModule : IModule { public void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterForNavigation<ViewA>(); } } ``` 3. 手动加载模块: ```csharp _moduleManager.LoadModule("ModuleAModule"); // [^4] ``` ### 四、视图模型定位 1. 自动关联View-ViewModel(命名约定): * `Views/ExampleView.xaml` * `ViewModels/ExampleViewModel.cs` 2. 手动绑定: ```csharp ViewModelLocationProvider.Register<CustomView, CustomViewModel>(); ``` ### 五、导航与通信 1. **区域管理**:通过`RegionManager`管理UI区域 2. **事件聚合器**:使用`IEventAggregator`实现松耦合通信 ```mermaid graph TD A[PrismApplication] --> B[依赖注入容器] B --> C[模块注册] C --> D[视图导航] D --> E[业务逻辑实现] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值