最近闲来无事又想搞搞WPF。。。。。
作个框架吧,可能又是半途而废。。。。老是坚持不下来css
不废话了,html
先看一下工程结构shell
布局大概是这样的express
SystemHeader | |
Aside | Main |
Footer |
PW.SystemHeader是用来放导航条,Log或者系统名称的bootstrap
PW.Aside是准备放每一个模块的树形菜单的,能够根据后续系统的须要作相应的变更和扩展app
PW.Login就是一个登录的模块了框架
PW.Footer只是一个底部的占位栏,须要的话能够放置一些显示信息ide
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的前辈给指教指教啊。。。。看到的朋友知道怎么弄能够给说一下啊,有好的方法,好的建议都能写下来啊,,,,感受本身实在是有点瞎弄啊