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


目录
  • Prism框架模块化思想、Shell、Region、Moduel
  • 简介
  • Shell
  • Region
    • Region的多种注册方式
      • 第一种:Xaml方式注册
      • 第二种通过C#代码注册
    • 创建自己的RegionAdapter
      • 定义RegionAdapter
      • 注册RegionAdapter
    • Region视图切换、Activate
    • Navigation
      • 基本导航
        • 第一种:基本导航
        • 第二种:使用参数替代字符串的导航
        • 第三种:使用TabControl
        • 第四种:判断窗口是否重现还是新增
        • 第五种:导航传值
        • 第六种:导航日志控制导航
        • 第七种:判断导航是否结束
        • 第八种:判断能不能导航过去:IConfirmNavigationRequest
        • 完整示例:
  • Model
    • 作用
    • 定义
    • 注册与发现
      • 配置文件注册
        • 配合App.config注册Module
        • 配合Xml文件注册Moddule
      • 代码注册
        • 代码基础注册
        • 代码按需加载
        • 代码IModuleManager任意对象中进行处理
      • 自动扫描目录注册
  • Dialog弹出窗口
    • 改变弹窗样式
    • 自定义弹窗
  • TabControl示例

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();
}

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方式注册



第二种通过C#代码注册

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



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
{
    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();
    }

    protected override void ConfigureRegionAdapterMappings(RegionAdapterMappings regionAdapterMappings)
    {
        base.ConfigureRegionAdapterMappings(regionAdapterMappings);

        regionAdapterMappings.RegisterMapping(Container.Resolve());
    }
}

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();
            _region.Add(_containerExtension.Resolve());
            _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();
  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("mmView");
     containerRegistry.RegisterForNavigation();

     containerRegistry.RegisterDialog();
 }
}

基本导航

第一种:基本导航

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

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

第三种:使用TabControl

  1. ViewModel增加属性Title
  2. 绑定到View
  3. 和第二中方法的导航一样可以注册到指定的Region内

    



    

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

继承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 _viewACommand;

public DelegateCommand ViewACommand
{
    get
    {
        if (_viewACommand == null)
            _viewACommand = new DelegateCommand((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 _viewACommand;

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

                    }),
                    param);
            });
        ;
        return _viewACommand;
    }
    set { _viewACommand = value; }
}

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

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

完整示例:

XAML


    
        
    
    
        
            
            
        
        
            

注册

public partial class App : PrismApplication
{
    protected override Window CreateShell()
    {
        return Container.Resolve();
    }

    protected override void RegisterTypes(IContainerRegistry containerRegistry)
    {
        containerRegistry.RegisterForNavigation();
        containerRegistry.RegisterForNavigation();
    }
}

ViewModel

public class NavigationWindowViewModel : BindableBase
{
    IRegionManager _regionManager;
    IRegionNavigationService _regionNavigationService;

    public NavigationWindowViewModel(IRegionManager regionManager, IRegionNavigationService regionNavigationService)
    {
        _regionManager = regionManager;
        _regionNavigationService = regionNavigationService;
    }

    private DelegateCommand _viewACommand;

    public DelegateCommand ViewACommand
    {
        get
        {
            if (_viewACommand == null)
                _viewACommand = new DelegateCommand((view) =>
                {
                    // 导航到 ViewA
                    // 传值
                    // 导航某个页面,添加判断,是否是可以导航过去
                    NavigationParameters param = new NavigationParameters();
                    param.Add("value", "123");
                    _regionManager.RequestNavigate("ContentRegion", view,
                        new Action((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


    
    

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;
    /// 
    /// =====================================================================INavigationAware========
    /// 
    /// 
    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 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();
        //Region
        region.RegisterViewWithRegion("LeftDockRegion", typeof(LeftMenuView));
        region.RegisterViewWithRegion("TopDockRegion", typeof(HeaderView));


        //containerProvider.Resolve().Register();
    }

    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" ?>

	
		
  1. 注册
    1. App.xaml.cs中重写ConfigureModuleCatalog
protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
{
    base.ConfigureModuleCatalog(moduleCatalog);

    moduleCatalog.AddModule();
    moduleCatalog.AddModule();
}
  1. 重新生成Module程序集,并把dll文件复制到Shell主程序文件目录下。

配合Xml文件注册Moddule

  1. 增加一个ModuleConfig.xml文件
<?xml version="1.0" encoding="utf-8" ?>

	

  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();
}

代码按需加载

  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();
    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();
        //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();
    }
}
  1. 实现对应的ViewModel,并实现IDialogAware接口
public class UserEditViewModel : IDialogAware
{
    public string Title => "用户信息编辑";

    public event Action 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修改弹窗样式,比较少用,一般使用的是自定义弹窗。

    


    


自定义弹窗

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

  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();
    //containerRegistry.RegisterDialogWindow("DialogWindow");
}
  1. 命令调用
OpenDialogCommand = new DelegateCommand(() =>
{
    DialogParameters param = new DialogParameters();
    // View的注册名称 - 参数键值对 - 弹窗回调 - 指定弹出窗口的注册名称
    dialogService.ShowDialog("UserEditView", param,
        (result) =>
        {

        });
});

TabControl示例

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


        
        
        
    

    
        
        
        
    

public class MenuManagementViewModel : BindableBase, INavigationAware
{
    private string UriPath = "";

    private string _title;

    public string Title
    {
        get { return _title; }
        set { _title = value; }
    }
    public DelegateCommand CloseCommand { get; private set; }
    public DelegateCommand SaveCommand { get; private set; }

    public MenuManagementViewModel(IRegionManager regionManager, IUnityContainer unityContainer, ICompositeCommands compositeCommands)
    {
        this.Title = "菜单管理";

        CloseCommand = new DelegateCommand((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("mmView");
        containerRegistry.RegisterForNavigation();


        containerRegistry.RegisterDialog();
    }
}