C# WPF Prsim PrsimOutlook学习记录(一)

本文详细介绍了如何使用Prsim和WPF构建PrsimOutlook项目,涉及模块化设计、Unity集成、RegionManager的使用以及自定义RegionAdapter实现。作者通过视频学习并实践了如何将View注册到不同Region,展示了Prsim的灵活性和依赖注入的优势。

最近在学习 Prsim 和WPF,在油管上找到了一个 PrsimOutlook 项目,作者是 Brian Lagunas ,是当年 Prsim 搬家到GitHub时交给社区的三位贡献者之一.

照着视频学习加上有源代码,作者就是Prsim的作者之一,对Prsim相当的了解.

相关链接

视频一 Setting up the Prism Project 学习记录

视频一 程序最后的结果是这样的
在这里插入图片描述

使用 Prsim 提供的扩展创建模板,使用此模板可以快速创建 Prsim项目和 Prsim Module

PrsimOutlook 是 Prsim WPF项目的空模板
Modules 目录下三个项目是 Prsim WPF Mudule 的空模板
PrsimOutlook.Core 是用来放 共享的一些的基础设施

创建程序目录结构如下

在这里插入图片描述

  • PrsimOutlook 是 Prsim WPF项目的空模板
  • Modules 目录下三个项目是 Prsim WPF Mudule 的空模板
  • PrsimOutlook.Core 是用来放 共享的一些的基础设施
窗体分为3个Region,定义在 PrismOutlook.Core.RegionNames 类中
namespace PrismOutlook.Core
{
    public static class RegionNames
    {
        public static string ContentRegion = "ContentRegion";
        public static string OutlookGroupRegion = "OutlookGroupRegion";
        public static string RibbonRegion = "RibbonRegion";
    }
}

在MainWindow.xaml中 使用这3个 Region
<ig:RibbonWindowContentHost>
    <ig:RibbonWindowContentHost.Ribbon>
        <ig:XamRibbon prism:RegionManager.RegionName="{x:Static core:RegionNames.RibbonRegion}">
            
        </ig:XamRibbon>
    </ig:RibbonWindowContentHost.Ribbon>

    <DockPanel LastChildFill="True">

        <ig:XamOutlookBar prism:RegionManager.RegionName="{x:Static core:RegionNames.OutlookGroupRegion}" DockPanel.Dock="Left" Width="200"></ig:XamOutlookBar>

        <ContentControl prism:RegionManager.RegionName="{x:Static core:RegionNames.ContentRegion}" />
    </DockPanel>

</ig:RibbonWindowContentHost>

最上方是 RibbonRegion ,左下侧是 OutlookGroupRegion,右侧是 ContentRegion

具体Region的内容,写在 Module中,这样可以降低耦合

首先将 PrsimOutlook 和Module 中的View 关联起来

这需要在App.xaml.cs override ConfigureModuleCatalog函数 添加 Module

 protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
 {
     moduleCatalog.AddModule<MailModule>();
     moduleCatalog.AddModule<ContactsModule>();
 }

其次需要在 MailModule.cs 和 ContactsModule.cs 中 将View 注册到视图上

由于Prsim有Unity,可以在通过这种方式获得 IRegionManager 的实例

		private readonly IRegionManager _regionManager;

        public MailModule(IRegionManager regionManager)
        {
            _regionManager = regionManager;   
        }

MailModule

namespace PrismOutlook.Modules.Mail
{
    public class MailModule : IModule
    {
        private readonly IRegionManager _regionManager;

        public MailModule(IRegionManager regionManager)
        {
            _regionManager = regionManager;   
        }

        public void OnInitialized(IContainerProvider containerProvider)
        {
            //TODO: remove
            _regionManager.RegisterViewWithRegion(RegionNames.ContentRegion, typeof(ViewA));


            _regionManager.RegisterViewWithRegion(RegionNames.RibbonRegion, typeof(HomeTab));
            _regionManager.RegisterViewWithRegion(RegionNames.OutlookGroupRegion, typeof(MailGroup));
        }

        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
            
        }
    }
}

ContactsModule

namespace PrismOutlook.Modules.Contacts
{
    public class ContactsModule : IModule
    {
        private readonly IRegionManager _regionManager;

        public ContactsModule(IRegionManager regionManager)
        {
            _regionManager = regionManager;
        }

        public void OnInitialized(IContainerProvider containerProvider)
        {
            _regionManager.RegisterViewWithRegion(RegionNames.OutlookGroupRegion, typeof(ContactsGroup));
        }

        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
            
        }
    }
}

这里面发现
ViewA 已经创建了,但 HomeTab , ContactsGroup , MailGroup 还没创建

MailGroup和 ContactsGroup 是注册到 OutlookGroupRegion
HomeTab 是注册到 RibbonRegion

现在要创建 MailGroup View

<ig:OutlookBarGroup x:Class="PrismOutlook.Modules.Mail.Menus.MailGroup"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:PrismOutlook.Modules.Mail.Menus"
             xmlns:ig="http://schemas.infragistics.com/xaml/wpf"
                    Header="Mail">
    <Grid>
        <TextBlock Text="Testing"/>
    </Grid>
</ig:OutlookBarGroup>

窗体类型是 OutlookBarGroup

现在创建 ContactsGroup

<ig:OutlookBarGroup x:Class="PrismOutlook.Modules.Contacts.Menus.ContactsGroup"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:PrismOutlook.Modules.Contacts.Menus"
             xmlns:ig="http://schemas.infragistics.com/xaml/wpf"
                    Header="Contacts">
    <Grid>
        <TextBlock Text="Tetsing again from Contacts" />
    </Grid>
</ig:OutlookBarGroup>

窗体类型也是 OutlookBarGroup

这里面有一个需要注意的地方,让我们回到 MainWindow.xaml

<ig:RibbonWindowContentHost>
    <ig:RibbonWindowContentHost.Ribbon>
        <ig:XamRibbon prism:RegionManager.RegionName="{x:Static core:RegionNames.RibbonRegion}">
            
        </ig:XamRibbon>
    </ig:RibbonWindowContentHost.Ribbon>

    <DockPanel LastChildFill="True">

        <ig:XamOutlookBar prism:RegionManager.RegionName="{x:Static core:RegionNames.OutlookGroupRegion}" DockPanel.Dock="Left" Width="200"></ig:XamOutlookBar>

        <ContentControl prism:RegionManager.RegionName="{x:Static core:RegionNames.ContentRegion}" />
    </DockPanel>

</ig:RibbonWindowContentHost>

Prsim 对于 ContentControl,可以自动的将View 注入到 Region中
但对于其他的控件,需要自己写 RegionAdapter
所以对于 XamOutlookBar 需要写 XamOutlookBar 控件的 RegionAdapter
对于这个 RegionAdapter 我还不清楚是怎么写的,好在我们有源码,直接copy过来看看

using Infragistics.Windows.OutlookBar;
using Prism.Regions;

namespace PrismOutlook.Core.Regions
{
    public class XamOutlookBarRegionAdapter : RegionAdapterBase<XamOutlookBar>
    {
        public XamOutlookBarRegionAdapter(IRegionBehaviorFactory factory)
            : base(factory)
        {

        }

        protected override void Adapt(IRegion region, XamOutlookBar regionTarget)
        {
            region.Views.CollectionChanged += ((x, y) =>
            {
                switch (y.Action)
                {
                    case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
                        {
                            foreach (OutlookBarGroup group in y.NewItems)
                            {
                                regionTarget.Groups.Add(group);

                                //The WPF XamOutlookBar does not automatically select the first group in it's collection.
                                //So we must manually select the group if it is the first one in the collection, but we don't
                                //want to excute this code every time a new group is added, only if the first group is the current group being added.
                                if (regionTarget.Groups[0] == group)
                                {
                                    regionTarget.SelectedGroup = group;
                                }
                            }
                            break;
                        }
                    case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
                        {
                            foreach (OutlookBarGroup group in y.OldItems)
                            {
                                regionTarget.Groups.Remove(group);
                            }
                            break;
                        }
                }
            });
        }

        protected override IRegion CreateRegion()
        {
            return new SingleActiveRegion();
        }
    }
}

一顿操作猛如虎,大意就是 往 XamOutlookBar 加入Region
对于这个项目来说也就是 往 XamOutlookBar 加入 MailGroup 和 ContactsGroup

同时还需要写 XamRibbonRegionAdapter
代码如下

using Infragistics.Windows.Ribbon;
using Prism.Regions;
using System;
using System.Collections.Specialized;

namespace PrismOutlook.Core.Regions
{
    public class XamRibbonRegionAdapter : RegionAdapterBase<XamRibbon>
    {
        public XamRibbonRegionAdapter(IRegionBehaviorFactory regionBehaviorFactory)
            : base(regionBehaviorFactory)
        {
        }

        protected override void Adapt(IRegion region, XamRibbon regionTarget)
        {
            if (region == null) throw new ArgumentNullException(nameof(region));
            if (regionTarget == null) throw new ArgumentNullException(nameof(regionTarget));

            region.Views.CollectionChanged += (s, e) =>
            {
                if (e.Action == NotifyCollectionChangedAction.Add)
                {
                    foreach (var view in e.NewItems)
                    {
                        AddViewToRegion(view, regionTarget);
                    }

                }
                else if (e.Action == NotifyCollectionChangedAction.Remove)
                {
                    foreach (var view in e.OldItems)
                    {
                        RemoveViewFromRegion(view, regionTarget);
                    }
                }
            };
        }

        protected override IRegion CreateRegion()
        {
            return new SingleActiveRegion();
        }

        static void AddViewToRegion(object view, XamRibbon xamRibbon)
        {
            if (view is RibbonTabItem ribbonTabItem)
            {
                xamRibbon.Tabs.Add(ribbonTabItem);
            }
        }

        static void RemoveViewFromRegion(object view, XamRibbon xamRibbon)
        {
            if (view is RibbonTabItem ribbonTabItem)
            {
                xamRibbon.Tabs.Remove(ribbonTabItem);
            }
        }
    }
}

然后还需要在 App.xaml.cs 中 告诉 Prsim 一下,注册一下

 protected override void ConfigureRegionAdapterMappings(RegionAdapterMappings regionAdapterMappings)
 {
     base.ConfigureRegionAdapterMappings(regionAdapterMappings);
     regionAdapterMappings.RegisterMapping(typeof(XamOutlookBar), Container.Resolve<XamOutlookBarRegionAdapter>());
     regionAdapterMappings.RegisterMapping(typeof(XamRibbon), Container.Resolve<XamRibbonRegionAdapter>());
 }
总结

一路写下来,思路一下清晰了起来,照着视频学的时候还是一片懵懂,我会坚持写下去的

视频一 主要是把 程序框架搭了起来,将Module注册到了 MainWindow中,这样 程序就知道了各个Module.
然后将 View 通过 RegisterViewWithRegion 注册到 各个Region中.
Prsim 是有Unity的,所以程序可以使用依赖注入的方式,很方便
对于 ContentControl,Prsim 为我们提供了默认的方式 将View 注册到Region中
但对于 其他的控件,就需要自己来写 RegionAdapter,同时还需要在 ConfigureRegionAdapterMappings中注册一下

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值