zoukankan      html  css  js  c++  java
  • Prism框架模块化思想、Shell、Region、Moduel

    Prism框架模块化思想、Shell、Region、Moduel

    简介

    这是一篇朝夕Jovan老师讲Prism的课堂学习笔记。


    1. PrismBootstrapper&PrismApplication【全局资源管控,项目启动】

    2. Shell:壳-》Window

    3. Region:区域

    4. Module:模块(View,ViewModel,Model)

    项目的基本结构:Shell=>Region=>Module

    Shell

    protected override Window CreateShell()
    {
        return Container.Resolve<NavigationWindow>();
    }
    

    Region

    如果只更新数据源,UI不变则可以使用prism:RegionManager.RegionContext=""

    一般的WPF容器是无法创建Region的,例如:Grid,UniformGrid,DockPanel,Canvas等。

    可以创建Region的,例如:

    1. ContentControl,只能显示一个,所有内容都是堆叠的。
    2. ItemsControl,所有内容都是栈的形式布局的,类似StackPanel
    3. ComboBox,所有内容,类似下拉框,下拉列表。
    4. TabControl,类似TabControl控件

    总结:具有RegionAdapter才可以创建Region,可以自定义Region

    ContentControl->ContentControlRegionAdapter

    ItemsControl->ItemsControlRegionAdapter

    ComboBox->SelectorRegionAdapter

    TabControl->TabControlRegionAdapter


    Region的多种注册方式

    第一种:Xaml方式注册

    <!--第一种情况,Xaml方式注册一个区域-->
    <!--<ContentControl prism:RegionManager.RegionName="ContentRegion"/>-->
    

    第二种通过C#代码注册

    Region中的都是UserControl,所以应该是创建一个ViewA,然后再添加到Region中。

    <!--第二种方式,代码注册-->
    <ContentControl Name="cc"/>
    
    public MainWindow(IRegionManager regionManager)
    {
        InitializeComponent();
        
        RegionManager.SetRegionName(this.cc, "ContentRegion");
        /// 将相关View指定到特定的Region
        /// 第一个参数:Region的名称
        /// 第二个参数:View的类型
        regionManager.RegisterViewWithRegion("ContentRegion", typeof(ViewA));
    }
    

    创建自己的RegionAdapter

    定义RegionAdapter

    public class StackPanelRegionAdapter : RegionAdapterBase<StackPanel>
    {
        public StackPanelRegionAdapter(IRegionBehaviorFactory regionBehaviorFactory) : base(regionBehaviorFactory)
        {
        }
    
        protected override void Adapt(IRegion region, StackPanel regionTarget)
        {
            region.Views.CollectionChanged += (se, ev) =>
            {
                if (ev.Action == NotifyCollectionChangedAction.Add)
                {
                    foreach (UIElement item in ev.NewItems)
                    {
                        regionTarget.Children.Add(item);
                    }
                }
            };
        }
    
        protected override IRegion CreateRegion() => new AllActiveRegion();
    }
    

    注册RegionAdapter

    public partial class App : PrismApplication
    {
        protected override Window CreateShell()
        {
            return Container.Resolve<NavigationWindow>();
        }
    
        protected override void ConfigureRegionAdapterMappings(RegionAdapterMappings regionAdapterMappings)
        {
            base.ConfigureRegionAdapterMappings(regionAdapterMappings);
    
            regionAdapterMappings.RegisterMapping<StackPanel>(Container.Resolve<StackPanelRegionAdapter>());
        }
    }
    

    Region视图切换、Activate

    Activate&Deactivate有针对,并不是所有Adapter适用,例如:ContentControlRegionAdapter可以,如果使用ItemsControlRegionAdapter则会报错。

    Region视图切换,Navigation。

    1. 构造函数注入IRegionManager,IContainerExtension
    2. 取出Region,_regionManager.Regions["ContentRegion"];
    3. 添加view
    4. 导航到指定view

    Activate&Deactivate有针对,并不是所有Adapter适用,ContentControlRegionAdapter可以,但是ItemsControlRegionAdapter->报错。

    public partial class MainView : Window
    {
        IRegionManager _regionManager;
        IContainerExtension _containerExtension;
        ViewB viewB;
        public MainView(IRegionManager regionManager, IContainerExtension containerExtension)
        {
            InitializeComponent();
            _regionManager = regionManager;
            _containerExtension = containerExtension;
    
            /// Region视图切换
            /// Activete&Deactivated
            /// 视图切换-》另一种方式:Navigation
            this.Loaded += (se, ev) =>
            {
                var _region = _regionManager.Regions["ContentRegion"];
    
                viewB = _containerExtension.Resolve<ViewB>();
                _region.Add(_containerExtension.Resolve<ViewA>());
                _region.Add(viewB);
            };
        }
    
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var _region = _regionManager.Regions["ContentRegion"];
            _region.Activate(ViewB);
    
            // Activate&Deactivate有针对,并不是所有Adapter适用
            // ContentControlRegionAdapter
            // ItemsControlRegionAdapter->报错
        }
    }
    

    判断View是否是活跃状态

    1. 继承BindableBase, IActiveAware
    2. 实现
    public class ViewAViewModel : BindableBase, IActiveAware, 
    {
        private bool _isActive;
        public bool IsActive
        {
            get => _isActive;
            set
            {
                _isActive = value;
    
                if (value)
                {
                    System.Diagnostics.Debug.WriteLine("ViewA 激活了");
                }
                else
                {
                    System.Diagnostics.Debug.WriteLine("ViewA 失效了");
                }
                IsActiveChanged?.Invoke(this, new EventArgs());
            }
        }
    
    	public event EventHandler IsActiveChanged;
    }
    

    Navigation控制View切换,

    1. 写View的UI代码
    2. 写ViewModels的代码
    3. 写对应的Cmd方法
    4. 注入View,App.cs 中的RegisterTypes,注入VIew,containerRegistry.RegisterForNavigation<ViewA>();
    5. ViewModel的构造函数中注入IRegionManager,需要的导航到指定的View:_regionManager.RequestNavigate("ContentRegion", "ViewB");

    如果是Module形式的注册,则可以在Module类中通过RegisterForNavigation注册

    public class SysModule : IModule
    {
     public void OnInitialized(IContainerProvider containerProvider)
     {
         
     }
    
     public void RegisterTypes(IContainerRegistry containerRegistry)
     {
         containerRegistry.RegisterForNavigation<MenuManagementView>("mmView");
         containerRegistry.RegisterForNavigation<UserManagementView>();
    
         containerRegistry.RegisterDialog<UserEditView>();
     }
    }
    

    基本导航

    第一种:基本导航

    _regionManager.RequestNavigate("ContentRegion", "ViewB");
    

    第二种:使用参数替代字符串的导航

    <Button Content="ViewA" Command="{Binding ViewACommand}" CommandParameter="ViewA"/>
        
    private DelegateCommand<string> _viewACommand;
    
    public DelegateCommand<string> ViewACommand
    {
        get
        {
            if (_viewACommand == null)
                _viewACommand = new DelegateCommand<string>((view) =>
                {
    				_regionManager.RequestNavigate("ContentRegion", view);
                });
            ;
            return _viewACommand;
        }
        set { _viewACommand = value; }
    }
    

    第三种:使用TabControl

    1. ViewModel增加属性Title
    2. 绑定到View
    3. 和第二中方法的导航一样可以注册到指定的Region内
    <Window.Resources>
        <Style TargetType="TabItem">
            <Setter Property="Header" Value="{Binding DataContext.Title}"/>
        </Style>
    </Window.Resources>
    
    <TabControl prism:RegionManager.RegionName="ContentRegion" Grid.Row="1"/>
        
    
    

    第四种:判断窗口是否重现还是新增

    继承INavigationAware,IsNavigationTarget方法控制

    1. INavigationAware,实现三个接口方法
      1. IsNavigationTarget:View是重现(返回True)还是新建(返回False)
      2. OnNavigatedTo:导航传值,导航日志
      3. OnNavigatedFrom:从这个页面到那个页面,关注的是出发时机。

    第五种:导航传值

    1. NavigationWindowViewModel中的ViewACommand传参

    2. ViewA中接收参数,OnNavigatedTo中:var param = navigationContext.Parameters["value"];

    //NavigationWindowViewModel中的Command
    private DelegateCommand<string> _viewACommand;
    
    public DelegateCommand<string> ViewACommand
    {
        get
        {
            if (_viewACommand == null)
                _viewACommand = new DelegateCommand<string>((view) =>
                {
                    // 导航到 ViewA
                    // 传值
                    // 导航某个页面,添加判断,是否是可以导航过去
                    NavigationParameters param = new NavigationParameters();
                    param.Add("value", "123");
                    _regionManager.RequestNavigate("ContentRegion", view,param);
                });
            ;
            return _viewACommand;
        }
        set { _viewACommand = value; }
    }
    
    
    //ViewA中的OnNavigatedTo
    public void OnNavigatedTo(NavigationContext navigationContext)
    {
        // 导航传值
        var param = navigationContext.Parameters["value"];
    
        // 历史记录
        _journal = navigationContext.NavigationService.Journal;
        //_journal.GoForward();
        //_journal.GoBack();
    }
    
    public bool IsNavigationTarget(NavigationContext navigationContext)
    {
        // 控件View是重现(返回True)还是新建(返回False)
        return true;
    }
    
    public void OnNavigatedFrom(NavigationContext navigationContext)
    {
        // navigationContext可以拿ViewA和ViewB两个对象
        // 触发时机
    }
    

    第六种:导航日志控制导航

    1. ViewAViewModel继承INavigationAware,实现对应的OnNavigatedTo
      1. 向前:journal.GoForward();
      2. 向后:journal.GoBack();
    2. ViewAViewModel实现字段IRegionNavigationJournal _journal;
    3. 添加一个Command调用_journal.GoBack();回到之前的页面

    也可以NavigationWindowViewModel构造函数注入,_regionManager也可以达到相同的控制效果

    1. 构造函数注入:IRegionNavigationService
    2. 实现ForwordCommand、BackCommand

    _regionManager也可以达到相同的控制效果

    IRegionManager _regionManager;
    IRegionNavigationService _regionNavigationService;
    
    public NavigationWindowViewModel(IRegionManager regionManager, IRegionNavigationService regionNavigationService)
    {
        _regionManager = regionManager;
        _regionNavigationService = regionNavigationService;
    }
    
    private DelegateCommand _forwordCommand;
    
    public DelegateCommand ForwordCommand
    {
        get
        {
            if (_forwordCommand == null)
                _forwordCommand = new DelegateCommand(() =>
                {
                    //if (_regionNavigationJournal.CanGoForward)
                    //    _regionNavigationJournal.GoForward();
    
                    var j = _regionManager.Regions["ContentRegion"].NavigationService.Journal;
                    //var j = _regionNavigationService.Journal;
                    if (j.CanGoForward)
                        j.GoForward();
                });
            return _forwordCommand;
        }
        set { _forwordCommand = value; }
    }
    
    
    
    private DelegateCommand _backCommand;
    
    public DelegateCommand BackCommand
    {
        get
        {
            if (_backCommand == null)
                _backCommand = new DelegateCommand(() =>
                {
                    //var j = _regionNavigationService.Journal;
                    var j = _regionManager.Regions["ContentRegion"].NavigationService.Journal;
                    if (j.CanGoBack)
                        j.GoBack();
                });
            return _backCommand;
        }
        set { _backCommand = value; }
    }
    
    IRegionNavigationJournal _journal;
    
    public DelegateCommand GoBackCommand { get; set; }
    
    public ViewAViewModel()
    {
        this.Title = "VIewA";
    
        GoBackCommand = new DelegateCommand(GoBack);
    }
    
    private void GoBack()
    {
        _journal.GoBack();
    }
    
    public void OnNavigatedTo(NavigationContext navigationContext)
    {
        // 导航传值
        var param = navigationContext.Parameters["value"];
    
        // 历史记录
        _journal = navigationContext.NavigationService.Journal;
        //_journal.GoForward();
        //_journal.GoBack();
    }
    

    第七种:判断导航是否结束

    _regionManager.RequestNavigate第三个参数表示导航结束,可以写个Action进行处理,是导航的最后一站。

    private DelegateCommand<string> _viewACommand;
    
    public DelegateCommand<string> ViewACommand
    {
        get
        {
            if (_viewACommand == null)
                _viewACommand = new DelegateCommand<string>((view) =>
                {
                    // 导航到 ViewA
                    // 传值
                    // 导航某个页面,添加判断,是否是可以导航过去
                    NavigationParameters param = new NavigationParameters();
                    param.Add("value", "123");
                    _regionManager.RequestNavigate("ContentRegion", view,
                        new Action<NavigationResult>((result) =>
                        {
    
                        }),
                        param);
                });
            ;
            return _viewACommand;
        }
        set { _viewACommand = value; }
    }
    

    第八种:判断能不能导航过去:IConfirmNavigationRequest

    1. 继承接口:IConfirmNavigationRequest
    2. 实现接口:ConfirmNavigationRequest
    public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
    {
        bool result = false;
        if (MessageBox.Show("数据没保存,是否离开", "确认", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
        {
            // 允许导航
            result = true;
        }
        // 不允许导航过来
        continuationCallback(result);
    }
    

    完整示例:

    XAML

    <Window x:Class="YuTang.PrismLesson.Views.NavigationWindow"
            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"
            xmlns:local="clr-namespace:YuTang.PrismLesson.Views"
            xmlns:prism="http://prismlibrary.com/"
            prism:ViewModelLocator.AutoWireViewModel="True"
            mc:Ignorable="d"
            Title="NavigationWindow" Height="450" Width="800">
        <Window.Resources>
            <Style TargetType="TabItem">
                <Setter Property="Header" Value="{Binding DataContext.Title}"/>
            </Style>
        </Window.Resources>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="40"/>
                <RowDefinition />
            </Grid.RowDefinitions>
            <StackPanel Orientation="Horizontal">
                <Button Content="ViewA" Command="{Binding ViewACommand}" CommandParameter="ViewA"/>
                <Button Content="ViewB" Command="{Binding ViewBCommand}"/>
                <Button Content="Forword" Command="{Binding BackCommand}"/>
                <Button Content="Back" Command="{Binding ForwordCommand}"/>
            </StackPanel>
            <ContentControl prism:RegionManager.RegionName="ContentRegion" Grid.Row="1"/>
            <!--<TabControl prism:RegionManager.RegionName="ContentRegion" Grid.Row="1"/>-->
        </Grid>
    </Window>
    
    

    注册

    public partial class App : PrismApplication
    {
        protected override Window CreateShell()
        {
            return Container.Resolve<NavigationWindow>();
        }
    
        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.RegisterForNavigation<ViewA>();
            containerRegistry.RegisterForNavigation<ViewB>();
        }
    }
    

    ViewModel

    public class NavigationWindowViewModel : BindableBase
    {
        IRegionManager _regionManager;
        IRegionNavigationService _regionNavigationService;
    
        public NavigationWindowViewModel(IRegionManager regionManager, IRegionNavigationService regionNavigationService)
        {
            _regionManager = regionManager;
            _regionNavigationService = regionNavigationService;
        }
    
        private DelegateCommand<string> _viewACommand;
    
        public DelegateCommand<string> ViewACommand
        {
            get
            {
                if (_viewACommand == null)
                    _viewACommand = new DelegateCommand<string>((view) =>
                    {
                        // 导航到 ViewA
                        // 传值
                        // 导航某个页面,添加判断,是否是可以导航过去
                        NavigationParameters param = new NavigationParameters();
                        param.Add("value", "123");
                        _regionManager.RequestNavigate("ContentRegion", view,
                            new Action<NavigationResult>((result) =>
                            {
    
                            }),
                            param);
                    });
                ;
                return _viewACommand;
            }
            set { _viewACommand = value; }
        }
    
    
        private DelegateCommand _viewBCommand;
    
        public DelegateCommand ViewBCommand
        {
            get
            {
                if (_viewBCommand == null)
                    _viewBCommand = new DelegateCommand(() =>
                    {
                        // 导航到 ViewB
                        _regionManager.RequestNavigate("ContentRegion", "ViewB");
                    });
                ;
                return _viewBCommand;
            }
            set { _viewBCommand = value; }
        }
    
    
    
        private DelegateCommand _forwordCommand;
    
        public DelegateCommand ForwordCommand
        {
            get
            {
                if (_forwordCommand == null)
                    _forwordCommand = new DelegateCommand(() =>
                    {
                        //if (_regionNavigationJournal.CanGoForward)
                        //    _regionNavigationJournal.GoForward();
    
                        var j = _regionManager.Regions["ContentRegion"].NavigationService.Journal;
                        //var j = _regionNavigationService.Journal;
                        if (j.CanGoForward)
                            j.GoForward();
                    });
                return _forwordCommand;
            }
            set { _forwordCommand = value; }
        }
    
    
    
        private DelegateCommand _backCommand;
    
        public DelegateCommand BackCommand
        {
            get
            {
                if (_backCommand == null)
                    _backCommand = new DelegateCommand(() =>
                    {
                        //var j = _regionNavigationService.Journal;
                        var j = _regionManager.Regions["ContentRegion"].NavigationService.Journal;
                        if (j.CanGoBack)
                            j.GoBack();
                    });
                return _backCommand;
            }
            set { _backCommand = value; }
        }
    }
    

    需要导航的内容

    ViewA.XAML

    <Grid>
        <TextBlock Text="ViewA" FontSize="30"/>
        <Button Content="Back" Command="{Binding GoBackCommand}" Height="40" Width="120"/>
    </Grid>
    

    ViewAViewModel.cs

    public class ViewAViewModel : BindableBase, IActiveAware, INavigationAware, IConfirmNavigationRequest
    {
        IRegionNavigationJournal _journal;
        public ViewAViewModel()
        {
            this.Title = "VIewA";
    
            GoBackCommand = new DelegateCommand(GoBack);
        }
        private void GoBack()
        {
            _journal.GoBack();
        }
    
        private string _title;
    
        public string Title
        {
            get { return _title; }
            set { SetProperty(ref _title, value); }
        }
    
        public DelegateCommand GoBackCommand { get; set; }
    
        // ===================================================IActiveAware
        private bool _isActive;
        public bool IsActive
        {
            get => _isActive;
            set
            {
                _isActive = value;
    
                if (value)
                {
                    System.Diagnostics.Debug.WriteLine("ViewA 激活了");
                }
                else
                {
                    System.Diagnostics.Debug.WriteLine("ViewA 失效了");
                }
                IsActiveChanged?.Invoke(this, new EventArgs());
            }
        }
    
        public event EventHandler IsActiveChanged;
        /// <summary>
        /// =====================================================================INavigationAware========
        /// </summary>
        /// <param name="navigationContext"></param>
        public void OnNavigatedTo(NavigationContext navigationContext)
        {
            // 导航传值
            var param = navigationContext.Parameters["value"];
    
            // 历史记录
            _journal = navigationContext.NavigationService.Journal;
            //_journal.GoForward();
            //_journal.GoBack();
        }
    
        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            // 控件View是重现(返回True)还是新建(返回False)
            return true;
        }
    
        public void OnNavigatedFrom(NavigationContext navigationContext)
        {
            // navigationContext可以拿ViewA和ViewB两个对象
            // 触发时机
        }
    
        // ========================================================================IConfirmNavigationRequest
        public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
        {
            bool result = false;
            if (MessageBox.Show("数据没保存,是否离开", "确认", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
            {
                // 允许导航
                result = true;
            }
            // 不允许导航过来
    
    
    
            continuationCallback(result);
        }
    }
    

    Model

    Model其实是一系列View的集合,是PrismApplication的扩展延伸。

    作用

    是资源管理的延伸(继承IModule实现的两个方法很好的体现出来),一个程序集里View的注册,有了Module,可以由Module分别进行View的注册,Module再在PrismApplication里进行注册。

    定义

    1. Model中创建View
    2. Model中创建一个Module的管理类,负责注册:MainModule
      1. 继承:IModule实现两个接口
        1. OnInitialized
        2. RegisterTypes
    [Module(ModuleName = "MainModule", OnDemand = false)]
    public class MainModule : IModule
    {
        public void OnInitialized(IContainerProvider containerProvider)
        {
            var region = containerProvider.Resolve<IRegionManager>();
            //Region
            region.RegisterViewWithRegion("LeftDockRegion", typeof(LeftMenuView));
            region.RegisterViewWithRegion("TopDockRegion", typeof(HeaderView));
    
    
            //containerProvider.Resolve<IContainerExtension>().Register<ILeftMenuModel, LeftMenuModel>();
        }
    
        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
    
        }
    }
    

    注册与发现

    配置文件注册

    配合App.config注册Module

    1. App.config,配置文件注册与发现Model**
      1. 添加configSections节点:碰到module节点,就会实例化Prism.Modularity.ModulesConfigurationSection,然后把module加载出来。
      2. 添加modules节点
      3. 添加module节点
        1. assemblyFile:程序集名
        2. moduleType:通过Type进行反射,程序集全名称+程序集名称
        3. moduleName:Module名
        4. startupLoaded:加载的时机
          1. fals 按需加载,需要了再加载
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
    	<configSections>
    		<section name="modules" type="Prism.Modularity.ModulesConfigurationSection, Prism.Wpf"/>
    	</configSections>
        <startup> 
            <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
        </startup>
    	<modules>
    		<module assemblyFile="YuTang.PrismLesson.MainModule.dll" 
    				moduleType="YuTang.PrismLesson.MainModule.MainModule, YuTang.PrismLesson.MainModule"
    				moduleName="MainModule" 
    				startupLoaded="True"/>
    	</modules>
    </configuration>
    
    1. 注册
      1. App.xaml.cs中重写ConfigureModuleCatalog
    protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
    {
        base.ConfigureModuleCatalog(moduleCatalog);
    
        moduleCatalog.AddModule<MainModule.MainModule>();
        moduleCatalog.AddModule<SysModule.SysModule>();
    }
    
    1. 重新生成Module程序集,并把dll文件复制到Shell主程序文件目录下。

    配合Xml文件注册Moddule

    1. 增加一个ModuleConfig.xml文件
    <?xml version="1.0" encoding="utf-8" ?>
    <m:ModuleCatalog xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                        xmlns:m="clr-namespace:Prism.Modularity;assembly=Prism.Wpf">
    	<m:ModuleInfo ModuleName="MainModule"
                      ModuleType="YuTang.PrismLesson.MainModule.MainModule, YuTang.PrismLesson.MainModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </m:ModuleCatalog>
    
    1. 需要注意App.xaml.cs中的CreateModuleCatalog返回值需要重新写
    protected override IModuleCatalog CreateModuleCatalog()
    {
        return new XamlModuleCatalog("ModuleConfig.xml");
    }
    

    代码注册

    代码基础注册

    1. 添加module引用
    2. App.xaml.cs中ConfigureModuleCatalog注册
    protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
    {
        base.ConfigureModuleCatalog(moduleCatalog);
        moduleCatalog.AddModule<MainModule.MainModule>();
    }
    

    代码按需加载

    1. 添加module引用
    2. App.xaml.cs中ConfigureModuleCatalog注册
    protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
    {
        base.ConfigureModuleCatalog(moduleCatalog);
        moduleCatalog.AddModule(new ModuleInfo
        {
            ModuleName = "MainModule",
            ModuleType = typeof(MainModule.MainModule).AssemblyQualifiedName,
            //加载时机 是否按需加载
            InitializationMode = InitializationMode.OnDemand
        });
    
    }
    

    代码IModuleManager任意对象中进行处理

    1. 添加module引用
    2. App.xaml.cs中ConfigureModuleCatalog注册
    3. 还有一个Module加载完成的事件
    protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
    {
        base.ConfigureModuleCatalog(moduleCatalog);
        // 任意对象中进行处理,通过对象的构造函数注入ModuleManager的实例
        IModuleManager moduleManager = null;
        moduleManager.LoadModule<MainModule.MainModule>();
        moduleManager.LoadModuleCompleted += (se, ev) => { };
    }
    

    自动扫描目录注册

    1. 手动把Module生成的dll,移动到指定目录
    2. 通过程序集=》属性=》生成=》配置生成路径指定
    3. 通过程序集=》属性=》生成事件=》配置生成路径
    1. 定义Module,通过特性控制是否按需加载
    [Module(ModuleName = "MainModule", OnDemand = false)]
    public class MainModule : IModule
    {
        public void OnInitialized(IContainerProvider containerProvider)
        {
            var region = containerProvider.Resolve<IRegionManager>();
            //Region
            region.RegisterViewWithRegion("LeftDockRegion", typeof(LeftMenuView));
        }
    
        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
    
        }
    }
    
    1. bin.debug中添加目录Modules

    2. 把module生成的dll,放到目录中

    3. App.xaml.cs中ConfigureModuleCatalog注册

    protected override IModuleCatalog CreateModuleCatalog()
    {
        // 扫描目录
        return new DirectoryModuleCatalog() { ModulePath = @".Modules" };
    }
    

    Dialog弹出窗口

    1. 添加一个用户控件(作为弹出窗口的内容)
    2. Module类中注册Dialog弹出窗口
    public class SysModule : IModule
    {
        public void OnInitialized(IContainerProvider containerProvider){ }
        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.RegisterDialog<UserEditView>();
        }
    }
    
    1. 实现对应的ViewModel,并实现IDialogAware接口
    public class UserEditViewModel : IDialogAware
    {
        public string Title => "用户信息编辑";
    
        public event Action<IDialogResult> RequestClose;
    
        //是否可以关闭
        public bool CanCloseDialog()
        {
            return true;
        }
    
        public void OnDialogClosed()
        {
            
        }
    
        public void OnDialogOpened(IDialogParameters parameters)
        {
            
        }
    }
    
    1. 构造函数注入:IDialogService,

      1. 包括Show、ShowDialog
      2. 第二个参数可以给弹出窗口传参
      3. 回调,是窗口状态(在弹出窗口的ViewModel中处理才可以)
    2. 创建打开命令,通过注入的IDialogService方法ShowDialog打开弹窗

    public DelegateCommand OpenDialogCommand { get; private set; }
    OpenDialogCommand = new DelegateCommand(() =>
    {
        DialogParameters param = new DialogParameters();
        // View的注册名称 - 参数键值对 - 弹窗回调 - 指定弹出窗口的注册名称
        dialogService.ShowDialog("UserEditView", param,
            (result) =>
            {
    
            });
    });
    

    改变弹窗样式

    1. 通过prism:Dialog.WindowStyle修改弹窗样式,比较少用,一般使用的是自定义弹窗。
    <prism:Dialog.WindowStyle>
        <Style TargetType="Window">
            <Setter Property="WindowStyle" Value="None"/>
            <Setter Property="Width" Value="500"/>
            <Setter Property="Height" Value="300"/>
            <Setter Property="SizeToContent" Value="Manual"/>
        </Style>
    </prism:Dialog.WindowStyle>
    <Grid >
        <TextBlock Text="UserEdit" FontSize="30"/>
    </Grid>
    
    

    自定义弹窗

    多个程序或地方使用,创建一个程序集。

    1. 添加一个窗口
      1. xaml文件中只处理样式
      2. .cs文件中继承接口IDialogWindow
    public partial class DialogWindow : Window, IDialogWindow
    {
        public DialogWindow()
        {
            InitializeComponent();
        }
    
        public IDialogResult Result { get; set; }
    }
    
    1. 在App.xaml.cs中注册
    protected override void RegisterTypes(IContainerRegistry containerRegistry)
    {
        containerRegistry.RegisterDialogWindow<DialogWindow>();
        //containerRegistry.RegisterDialogWindow<DialogWindow>("DialogWindow");
    }
    
    1. 命令调用
    OpenDialogCommand = new DelegateCommand(() =>
    {
        DialogParameters param = new DialogParameters();
        // View的注册名称 - 参数键值对 - 弹窗回调 - 指定弹出窗口的注册名称
        dialogService.ShowDialog("UserEditView", param,
            (result) =>
            {
    
            });
    });
    

    TabControl示例

    实现一个TabControl,带关闭按钮。

    <Window.Resources>
            <Style TargetType="Button" x:Key="TabCloseButtonStyle">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="Button">
                            <Border VerticalAlignment="Center" HorizontalAlignment="Center" CornerRadius="3" Background="Transparent"
                                    Name="back">
                                <Path Data="M0 0 8 8M0 8 8 0" Margin="5"
                                      Stroke="{TemplateBinding Foreground}" StrokeThickness="1"/>
                            </Border>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsMouseOver" Value="True">
                                    <Setter Property="Background" Value="#19000000" TargetName="back"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
            
            <Style TargetType="TabItem">
                <Setter Property="Header" Value="{Binding DataContext.Title}"/>
                <Setter Property="Background" Value="Transparent"/>
                <Setter Property="Margin" Value="2,0"/>
                <Setter Property="Foreground" Value="#444"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="TabItem">
                            <Grid Background="{TemplateBinding Background}" Height="30">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition/>
                                    <ColumnDefinition Width="30"/>
                                </Grid.ColumnDefinitions>
                                <TextBlock Text="{TemplateBinding Header}" VerticalAlignment="Center" Margin="10,5,5,5"/>
                                <Button Grid.Column="1" Style="{StaticResource TabCloseButtonStyle}" Foreground="{TemplateBinding Foreground}"
                                        Visibility="Collapsed" Name="close_btn"
                                        Command="{Binding DataContext.CloseCommand}"/>
                            </Grid>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsMouseOver" Value="True">
                                    <Setter Property="Visibility" Value="Visible" TargetName="close_btn"/>
                                </Trigger>
                                <Trigger Property="IsSelected" Value="True">
                                    <Setter Property="Visibility" Value="Visible" TargetName="close_btn"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
                <Style.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Background" Value="#EEE"/>
                    </Trigger>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter Property="Background" Value="orange"/>
                        <Setter Property="Foreground" Value="White"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </Window.Resources>
    <Grid>
        <DockPanel>
            <ContentControl DockPanel.Dock="Left" Width="220" prism:RegionManager.RegionName="LeftDockRegion"/>
            <ContentControl DockPanel.Dock="Top" Height="80" prism:RegionManager.RegionName="TopDockRegion"/>
            <TabControl prism:RegionManager.RegionName="ContentRegion"/>
        </DockPanel>
    </Grid>
    
    public class MenuManagementViewModel : BindableBase, INavigationAware
    {
        private string UriPath = "";
    
        private string _title;
    
        public string Title
        {
            get { return _title; }
            set { _title = value; }
        }
        public DelegateCommand<string> CloseCommand { get; private set; }
        public DelegateCommand SaveCommand { get; private set; }
    
        public MenuManagementViewModel(IRegionManager regionManager, IUnityContainer unityContainer, ICompositeCommands compositeCommands)
        {
            this.Title = "菜单管理";
    
            CloseCommand = new DelegateCommand<string>((param) =>
            {
                // 把所在Region里面的当前ViewModel对应的View移除掉
                // 操作Region
    
                // 通过Unity顶层容器获取对应的类型
                var obj = unityContainer.Registrations.Where(v => v.Name == UriPath).FirstOrDefault();
                string name = obj.MappedToType.Name;
                if (!string.IsNullOrEmpty(name))
                {
                    var region = regionManager.Regions["ContentRegion"];
                    var view = region.Views.Where(v => v.GetType().Name == UriPath).FirstOrDefault();
                    if (view != null)
                        region.Remove(view);
                }
            });
    
            SaveCommand = new DelegateCommand(() =>
            {
                // 菜单保存
            });
            compositeCommands.DoCommand.RegisterCommand(SaveCommand);
        }
    
        public void OnNavigatedTo(NavigationContext navigationContext)
        {
            UriPath = navigationContext.Uri.ToString();
        }
    
        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            return true;
        }
    
        public void OnNavigatedFrom(NavigationContext navigationContext)
        {
    
        }
    }
    
    public class SysModule : IModule
    {
        public void OnInitialized(IContainerProvider containerProvider)
        {
            
        }
    
        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.RegisterForNavigation<MenuManagementView>("mmView");
            containerRegistry.RegisterForNavigation<UserManagementView>();
    
    
            containerRegistry.RegisterDialog<UserEditView>();
        }
    }
    
    登峰造极的成就源于自律
  • 相关阅读:
    有关系统架构的高可用原则
    Redis面试篇 -- 如何保证缓存与数据库的双写一致性?
    Redis面试篇 -- Redis常见性能问题和解决方案?
    Redis面试篇 -- Redis主从复制原理
    Python3如何安装pip工具?
    Redis面试篇 -- Redis持久化的方式有哪些?优缺点分别是什么?
    Linux在丢失的情况下重置密码
    APC (Asynchronous Procedure Call)
    eigenface资料整合
    python+opencv模拟生成运动模糊核
  • 原文地址:https://www.cnblogs.com/fishpond816/p/15216767.html
Copyright © 2011-2022 走看看