基于MVVM设计模式的Prism框架

一、前言

Prism 是一个用于构建富客户端桌面(WPF)和移动(Xamarin Forms)应用程序的框架,由微软提供。它基于微软的模式与实践(Microsoft Patterns & Practices)团队开发,并且是开源的。Prism 旨在简化应用程序开发过程,特别是那些遵循 MVVM(Model-View-ViewModel)模式的应用程序。
Prism框架的主要特点有模块化MVVM 支持依赖注入导航事件聚合器命令行为服务定位器视图模型定位器区域和布局配置和初始化等。

1、模块化:Prism 支持模块化应用程序设计,允许开发者将应用程序拆分成多个模块,每个模块包含自己的功能和视图。
2、MVVM 支持:Prism 深度集成了 MVVM 模式,提供了数据绑定、命令、事件聚合器等支持,简化了 ViewModel 和 View 之间的交互。
3、依赖注入:Prism 与依赖注入(DI)容器紧密集成,方便管理应用程序中的依赖关系和生命周期。
4、导航:Prism 提供了一个强大的导航服务,允许开发者定义和执行导航流程,支持参数传递和导航历史记录。
5、事件聚合器:Prism 提供了一个事件聚合器,简化了发布-订阅模式的实现,方便组件之间的松耦合通信。
6、命令:Prism 提供了多种命令实现,如 DelegateCommand 和 RelayCommand,简化了 ViewModel 中命令的创建和使用。
7、行为:Prism 引入了行为(Behaviors)的概念,允许开发者在不修改 ViewModel 的情况下,为 View 添加附加行为。
8、服务定位器:Prism 提供了一个服务定位器模式的实现,方便在应用程序中查找和使用服务。
9、视图模型定位器:Prism 提供了视图模型定位器,简化了视图模型的实例化和注册过程。
10、区域和布局:在 WPF 中,Prism 支持区域(Regions)的概念,允许开发者定义动态内容区域,可以在运行时加载和显示不同的视图。
11、配置和初始化:Prism 提供了配置和初始化模块和服务的机制,使得应用程序的启动和配置更加灵活。

以下是深入了解Prism源码或者使用包的地址。
GitHub:https://github.com/PrismLibrary/Prism
NuGet:https://www.nuget.org/packges/Prism.Wpf
Visual Studio Extension:Prism Template Pack
此外,附加一张Prism初始化的顺序流程图:
Prism流程图

二、区域(Region)

区域是 Prism 中实现用户界面组合的一个关键概念。它允许开发者定义应用程序界面中的功能区域,并在运行时动态地向这些区域添加内容。区域可以包含在 ContentControl、ItemsControl 和 TabControl 等控件中 。

1、定义区域(Region)的几种写法

定义区域(Region)的方法主要有两种,一种是在XAML界面指定(RegionManager.RegionName),另一种是在代码(Code)中指定(RegionManager.SetRegionName)。
在实现界面指定或者代码指定之前我们需要先在App.xaml.cs类中创建启动界面,并在MainWindowViewModel.cs类(ViewModel)中实现新区域(ViewA界面)的指定,以下是对应的cs代码。

// App.xaml.cs类 创建界面方法
private override Window CreateShell()
{
	// Prism框架中使用官方提供的容器实现界面的创建
	return Container.Resolver<MainWidnow>();
}
// MainWindowViewModel.cs类(ViewModel) 构造函数
private readonly IRegionManager regionManager;
public MainWindowViewModel(IRegionManager regionManager)
{
	this.regionManager = RegionManager;
	regionManager.RegisterViewWithRegion("ContentRegion",typeof(ViewA));
}

①XAML界面指定(RegionManager.RegionName)

XAML代码

<!-- MainWindow界面(View) -->
<Grid>
	<ContentControl prism:RegionManager.RegionName="ContentRegion" />
</Grid>

在以上例子中,我们在MainWindow界面创建了一个简单的区域(RegionManager)并在cs代码中将注册的这个区域绑定到一个新的界面上(ViewA),实现界面的展示。

②代码中指定(RegionManager.SetRegionName)

XAML代码

<!-- MainWindow界面(View) -->
<Grid>
	<ContentControl x:Name:"ctr" />
</Grid>

C#代码

// MainWindow.cs类(View) 构造函数
public MainWindow()
{
	InitializeComponent();
	regionManager.SetRegionName(ctr, "ContentRegion");
}

在以上例子中,界面上通过对区域的命名(ctr),cs代码中通过Name属性找到对应的控件,并通过SetRegionName的方式实现区域的绑定。

2、RegionManager

RegionManager 是 Prism 框架中的核心组件之一,它负责管理 WPF 应用程序中的区域(Region)。区域是应用程序界面中可以动态加载和显示内容的容器。
RegionManager主要的作用有定义区域(RegionManager.RegionName)维护区域集合(regionManager.Regions)提供对区域的访问(regionManager.Regions[“MyRegion”])合成视图(RegisterViewWithRegion(“MyRegion”, typeof(MyView)))区域导航(RequestNavigate(“MyRegion”, “MyView”)) 等。
以下是他们代码的写法示例。

①定义区域(RegionManager.RegionName)

<ContentControl prism:RegionManager.RegionName="MyRegion" />

在 XAML 中使用 RegionManager.RegionName 附加属性为控件指定区域名称

②维护区域集合(regionManager.Regions)

var regions = regionManager.Regions;

通过 RegionManager.Regions 属性可以访问所有区域的集合。

③提供对区域的访问(regionManager.Regions[“MyRegion”])

var region = regionManager.Regions["MyRegion"];

通过 RegionManager.Regions[regionName]索引器获取对特定名称区域的引用。

④合成视图(RegisterViewWithRegion(“MyRegion”, typeof(MyView)))

regionManager.RegisterViewWithRegion("MyRegion", typeof(MyView));

AutoPopulateRegionBehavior 自动填充行为,当附加到区域时,自动实例化并添加注册到该区域的视图类型。

⑤区域导航(RequestNavigate(“MyRegion”, “MyView”))

regionManager.RequestNavigate("MyRegion", "MyView");

通过调用 RequestNavigate 方法并传入区域名称和视图名称以触发导航。

3、RegionAdapter

RegionAdapter 是 Prism 框架中的一个概念,它的作用是将 WPF 控件适配为可以包含动态内容的区域(Region)。
以下是一个将StackPanel控件添加适配器的过程。
XAML代码

在这里插入代码片

C#代码

// App.xaml.cs类中添加一个注册区域适配器的方法
protected override void ConfigureRegionAdapterMappings(RegionAdapterMappings regionAdapterMappings)
{
	base.ConfigureRegionAdapterMappings(regionAdapterMappings);
	regionAdapterMappings.RegisterMapping(typeof(StackPanel), Container.Resolve<StackPanelRegionAdater >);
}

// 创建一个StackPanelRegionAdapter.cs类
// 基于StackPanel的区域适配器
public class StackPanelRegionAdater : RegionAdaterBase<StackPanel>
{
	public StackPanelRegionAdater(TRegionRehaviorFactory regionBehaviorFactory)
	{
	}
	
	// 若检测到StackPanel中有新增元素则将新元素新增到StackPanel内
	protected override void Adapt(IRegion region, StackPanel regionTarget)
	{
		region.Views.CollectionChange += (s, e) =>
		{
			if(e.Action == System.Collections.Specialized.NotifyCollectionChangeAction.Add)
			{
				foreach(FrameworkElement item in e.NewItems)
				{
					regionTarget.children.Add(item);
				}
			}
		};
	}

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

以上示例中,在App.xaml.cs类中通过重写ConfigureRegionAdapterMappings方法,在方法内添加了对StackPanel适配的适配器,实现StackPanel也能适配区域的效果。
在我们创建的StackPanelRegionAdapter.cs类中,主要重写了Adapt,以实现具体的适配方法与效果,这里我们通过校验当前是否是添加命令,是添加命令的前提下对整个数据源进行遍历,并将这些新的元素添加到StackPanel内。

三、模块(Module)

在 Prism 框架中,模块(Module) 是一种用于构建大型应用程序的方式,它将应用程序拆分成更小、更易于管理的部分。每个模块包含一组相关的功能、视图、视图模型、服务和资源。模块化有助于降低应用程序的复杂性,提高可维护性和可扩展性。

1、为什么有模块

在一个解决方案中,通常有一个主项目,其中包含很多视图,如下图所示。

基本解决方案图示
在此示例中,有很明显的嵌套关系,导致的程序之间的相互依赖。此等设计会导致项目有较高的耦合性,在Prism框架中,为了降低此等情况的耦合,出现了模块的概念。Prism框架中,将每个视图分开成多个单独的模块,设计图如下。
模块、项目关系图
在这个图示中,一个解决方案下有一个主项目和多个模块项目,可以明显看出主项目和模块项目之间没有直接的联系,来降低了程序的耦合性。每个模块项目指向主项目的内容区域,实现主项目调用模块项目实现界面展示。如下图所示。
模块、项目关系图

2、创建模块的方法

在Prism源码中可以看到,创建模块主要支持五种方式,分别是AppConfig(配置文件)、Code(代码)、Directory(字典)、LoadManual(手动加载)、XAML(界面)。

① AppConfig(配置文件)

配置文件创建模块的方法,要在配置文件添加上配置,如下。

<configuration>
	<configurations>
		<section name="modules" type="prism.Modularity.ModulesConfigurationsection, prism.Wpf" />
	</configurations>
	<startup>
	</startup>
	<modules>
		<module assemblyFile="ModuleA.dll" moduleType="ModuleA.ModuleAModule, ModuleA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="ModuleAModule" startupLoaded="True" />
	</modules>
</configuration>

在以上代码中,先添加了一个prism框架的模块引用,然后在模块引用中指向了ModuleA.dll模块,并以ModuleA为加载启动项。

② Code(代码)

代码的方式创建模块则只需要在App.xaml.cs类中的方法内添加绑定,如下。

protected override void ConfigureModuleCatalog(IModduleCatalog moduleCatalog)
{
	moduleCatalog.AddModule<ModuleA.ModuleAModule>();
}

以上代码中,通过重写ConfigureModuleCatalog方法,并在其内调用AddModule方法注入ModuleA模块,是实现模块创建。

③ Directory(字典)

字典的方式创建模块只需要在App.xaml.cs类中的方法重写,返回一个新的对象就行了,如下。

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

以上代码中,方法返回一个新的对象,对象中传出Modules的地址,再由界面上区域的Name使得ModuleA中的ViewModel能够将该区域注册为显示ViewA,实现ViewA界面的显示。

④ LoadManual(手动加载)

手动加载主要是通过LoadManual方法,手动调用模块创建,如下。
XAML页面代码

<DockPanel LastChildFill="True">
    <Button DockPanel.Dock="Top" Content="Load Module" Click="Button_Click" />
    <ContentControl prism:RegionManager.RegionName="ContentRegion" />
</DockPanel>

C#代码

// App.xaml.cs类中的方法 
// 注册模块
protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
{
    var moduleAType = typeof(ModuleAModule);
    moduleCatalog.AddModule(new ModuleInfo()
    {
        ModuleName = moduleAType.Name,
        ModuleType = moduleAType.AssemblyQualifiedName,
        InitializationMode = InitializationMode.OnDemand
    });
}

// MainWindow.xaml.cs类中的方法 
// 手动加载模块
private void Button_Click(object sender, RoutedEventArgs e)
{
    _moduleManager.LoadModule("ModuleAModule");
}

以上示例是通过界面的点击事件,触发代码手动调用模块ModuleAModule创建,实现了模块调用。此外,这里在方法手动加载之前需要先在App.xaml.cs类中将这个对象注册到实例中。

⑤ XAML(界面)

界面加载模块主要是通过新建一个界面来存储需要创建的模块的信息,再由配置文件进行注册,如下。

<!-- App.config -->
<configSections>
  <section name="modules" type="Prism.Modularity.ModulesConfigurationSection, Prism.Wpf" />
</configSections>
<startup>
</startup>
<modules>
  <module assemblyFile="ModuleA.dll" moduleType="ModuleA.ModuleAModule, ModuleA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="ModuleAModule" startupLoaded="True" />
</modules>

<!-- ModuleCatalog.xaml -->
<m:ModuleInfo ModuleName="ModuleAModule" 
              ModuleType="ModuleA.ModuleAModule, ModuleA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />

以上代码中,先有App.config文件注册一个ModuleA.dll文件,并指向Name为ModuleAModule模块,再创建ModuleCatalog.xaml并存放该模块的信息,最终实现模块的创建。

3、视图注入

在 Prism 框架中,视图注入(View Injection)是一种技术,允许将视图(View)与模块(Module)动态地关联到应用程序的用户界面中。这种机制使得应用程序可以在运行时加载和显示来自不同模块的视图,而不需要在编译时静态地引用它们。

public class ModuleAModule : IModule
{
	// 初始化时访问区域并对区域进行导航
	public void OnInitialized(IContainerProvider containerProvider)
	{
		var regionManager = containerProvider.Resolve<IRegionManager>();
		var region = regionManager.Regions["ContentRegion"];
		region.RequestNavigate("ViewA");
	}
	
	// 注册视图
	publi void RegisterTypes(IContainerRegistry containerRegistry)
	{
		containerRegistry.RegisterForNavigation<ViewA>();
	}
}

以上代码示例中,先视图ViewA注册,再在初始化的时候先找到对应区域,然后对该区域进行导航到视图ViewA,实现了视图注入操作,可以动态的对视图进行注入操作。

四、MVVM

Prism框架作为MVVM设计模式下的一种框架,其中MVVM也有其他的框架,每个框架有不同的支持内容,以下是Prism与MVVM几个较为经典的框架的功能对比表。

功能 \ 通知PrismMvvmlighrMicorosoft.Toolkit.Mvvm
通知BindadleBaseViewModelBaseObservableObject
命令DelegateCommandRelayCommandAsync/RelayCommand
聚合器IEventAggregatorIMessengerIMessenger
模块化××
容器××
依赖注入××
导航××
对话××

1、绑定(BindableBase)

如果在此之前,用mvvmlight框架的话,ViewModel继承的类如下:

public class TestViewModel : ViewModelBase
{
	private string _message;
	public string Message
	{
		get { return _message; }
		set { _message = value; RaisePropertyChanged(); }
	}
}

在Prism当中,需要继承于BindableBase,如下所示:

public class TestViewModel : BindableBase
{
	private string _message;
	public string Message
	{
		get { return _message; }
		set { _message = valule; RaisePropertyChanged(); }
	}
}

2、命令

在mvvmlight/microsoft.toolkit.mvvm中,声明Command,如下:

public class TestViewModel : ViewModelBase
{
	public RelayCommand SednCommand { get; set; }
	public RelayCommand<string> SednMessageCommand { get; set; }
}

在Prism中,可以使用DelegateCommand及带参数的Command,如下:

public class TestViewModel : ViewModelBase
{
	public DelegateCommand SednCommand { get; set; }
	public DelegateCommand<string> SednMessageCommand { get; set; }
}

根据以上描述,在Prism框架下实现一个简单的绑定和命令的示例,如下:
XAML界面代码

<UserControl
	...
	Prism:ViewModelLocator.AutoWireViewModel="True"/>
	<Grid>
		<StackPanel>
			<Button Command="{Binding OpenCommand}" Content="UpdateText" />
			<TextBlock FontSize="38" Text="{Binding Title}" />
		</StackPanel>
	</Grid>
</UserControl>

C#代码

public class ViewAViewMOdel : BindableBase
{
	public ViewAViewModel()
	{
		Title = "Hello!";
		OpenCommand - new DelegateCommand(() =>
		{
			Title = "Prism";
		});
	}
	
	private string _title
	
	public string Title
	{
		get { return _title; }
		set { _title = value; RaisePropertyChanged(); }
	}

	piblic DelegateCommand OpenCommand { get; private set; }
}

以上代码中,界面通过AutoWireViewModel置为True实现自动绑定,但是前提是View必须在同一目录下的Views文件夹内,ViewModel必须在同一目录下的ViewModels文件夹内。以上示例中通过界面点击触发OpenCommand事件,事件触发将界面上绑定的Title属性的值变更。

3、复合命令(CompositeCommand)

在 Prism 框架中,复合命令(Composite Command)是一种特殊类型的命令,它允许将多个 ICommand 对象组合成一个单一的命令。这样,当触发复合命令时,所有包含的命令都会被执行。这种命令模式非常有用,特别是在需要根据单一用户界面操作(如点击一个按钮)执行多个操作的场景中。
当界面触发了事件后,会去执行复合命令,然后复合命令通知各个单独的命令,实现命令的实现,如下图。
多触发器触发关系
当其中有一个子命令不能执行的情况,复合命令也会无法执行,界面上也无法触发该复合命令,如下图。
有不可执行的事件情况

public class ViewAViewMOdel : BindableBase
{
	public ViewAViewModel()
	{
		Title = "Hello!";
		OpenCommand1 - new DelegateCommand(() =>
		{
			Title += “OpenCommand1 \r\n”;
		});
		OpenCommand2 - new DelegateCommand(() =>
		{
			Title += “OpenCommand2 \r\n”;
		});

		// 将两个命令注册到复合命令内
		OpenAll = new CompositeCommand();
		OpenAll.RegisterCommand(OpenCommand1);
		OpenAll.RegisterCommand(OpenCommand2);
	}
	
	private string _title
	
	public string Title
	{
		get { return _title; }
		set { _title = value; RaisePropertyChanged(); }
	}

	piblic DelegateCommand OpenCommand1 { get; private set; }
	piblic DelegateCommand OpenCommand2 { get; private set; }
	piblic DelegateCommand OpenAll { get; private set; }
}

在以上示例中,我们实现了OpenCommand1 和OpenCommand2事件,再将这两个事件注册到OpenAll事件内,实现触发OpenAll事件就同时依次触发了OpenCommand1和OpenCommand2事件,实现了将OpenCommand1和OpenCommand2事件复合到OpenAll事件的复合事件。

五、事件聚合器(Eevent Aggregator)

在 Prism 框架中,事件聚合器(Event Aggregator)是一个设计模式,用于实现发布-订阅(Publish-Subscribe)模式的松耦合通信机制。事件聚合器作为中央事件处理系统,允许对象间进行交互而不需要直接引用彼此,这有助于降低系统的耦合度并提高模块化。如图:
事件聚合器

1、事件过滤器(IEventAggregator)

事件过滤器是用于控制发布事件的,可以通过一些参数对发布的信息进行控制,只发布过滤过后的信息。如图:
事件过滤器
图例中过滤了Id等于1和3的事件发布,只有Id是2的时候才会发布信息

XAML界面代码

<Grid>
	<StackPanel>
		<Button Command="{Binding OpenCommand}" Content="订阅"/>
		<Button Command="{Binding SendCommand}" Content="发布" />
		<TextBlock FontSize="38" Text="{Binding Title}" />
	</StackPanel>
</Grid>

C#代码

public class ViewAViewMOdel : BindableBase
{
	public ViewAViewModel(IEventAggregator eventAggregator)
	{
		SubscribeCommand = new DelegateCommand(() =>
		{
			// 不需要过滤事件的情况
			// eventAggregator.GetEvent<MessageEvent>().Subscribe(OnMessageReeived);
			// 增加过滤器的情况
			eventAggregator.GetEvent<MessageEvent>().Subscribe(OnMessageReeived, ThreadOption.PublisherThread, false, msg =>
			{
				if(msg.Equals("Hello"))
				{
					return true;
				}
				else
				{
					return false;
				}
			);
		});

		SendCommand = new DelegateCommand(() =>
		{
			eventAggregator.GetEvent<MessageEvent>().Publish("Hellow~~~~~");
		});

		this.eventAggregator = eventAggregator;
	}
	
	public void OnMessageReceived(string message)
	{
		Title += message + "\r\n";
	}
 
 	private string _title;
 	private readonly IEventAggreator eventAggregator;

	public string Title
	{
		get { return _title; }
		set { _title = value; RaisePropertyChanged(); }
	}

	public DelegateCommand SubscribeCommand { get; private set; }

	public DelegateCommand SendCommand { get; private set; }
}

public class MessageEvent : PubSubEvent<string>
{

}	

以上代码示例中,订阅是增加了过滤机制,过滤后只显示公共线程的数据,且每次订阅完成后都会垃圾回收掉资源,且只有msg 是”Hello“的情况才会订阅。

2、订阅取消

除此之外,聚合器还提供了订阅取消的方法。

SendCommand = new DelegateCommand(() =>
{
	eventAggregator.GetEvent<MessageEvent>().Unsubscribe(OnMessageReceived);
}

在以上示例中,当触发了发布事件后,将会取消先前的订阅事件,实现订阅的动态取消。

六、导航(Navigation)

在 Prism 框架中,导航是一个核心概念,它允许应用程序在运行时动态地加载和显示不同的视图(View)。这种机制使得用户界面可以更加灵活和动态,类似于单页面应用程序(SPA)的体验。

1、翻页

导航功能可以通过事件的方法触发,导航到新的视图处。

// App.xaml.cs 
public override void RegisterTypes(IContainerRegistry containerRegistry)
{
	containerRegistry.RegisterForNavigation<ViewA>("PageA");
	containerRegistry.RegisterForNavigation<ViewB>();
}

// MainWindowViewModel.cs
public MainWindowViewModel(IRegionManager regionManager)
{
	OpenACommand = new DelegateCommand(OpenA);
	OpenBCommand = new DelegateCommand(OpenB);
	this.regionManager = regionManager;
}

public void OpenA()
{
	regionManager.ReqyestNavigate("ContentRegion", "PageA");
}	

public void OpenB()
{
	regionManager.ReqyestNavigate("ContentRegion", "ViewA");
}	

以上示例中,显示在App.xaml.cs类中注册了ViewA和ViewB视图,并将ViewA取别名为PageA,在后面MainWindowViewModel.cs类中,通过触发OpenACommand事件来调用OpenA方法来实现了PageA界面的跳转展示。

2、传参

在导航到新页面的时候可以由当前页的ViewModel给新页面传递部分参数,具体实现如下。

// MainWindowViewModel.cs
private void OpenA()
{
	// 另一种传参方式
	// regionManger.RequestNavigate("ContentRegion", $"PageA?Value=Hello");

	NavigationParameters param = new NavigationParameters();
	param.Add("Value", "Hello");
	regionManager.RequestNavigate("ContentRegion", "PageA", param);
}

// ViewAViewModel.cs
public class ViewAViewModel : BindableBase, INavigationAware
{
	private string _title;

	public string Title
	{
		get { return _title; }
		set { _title = value; RaisePropertyChanged(); }
	}
	
	public bool IsNavigationTarget(NavigationContext navigationContext)
	{
		return true;
	}
	
	public void OnNavigatedFrom(NavigationContext navigationContext)
	{
	}

	public void OnNavigatedTo(NavigationContext navigationContext)
	{
		Title = navigationContext.Parameters.GetValue<string>("Value");
	}
}

以上示例中,通过在导航到ViewA视图前传入一个Vlaue值,来实现界面ViewA展示Value值的功能。在此情况下ViewA需要创建一个ViewAViewModel来执行这些逻辑控制,此类需要继承自INavigationAware以实现导航的功能,在重写的OnNavigatedTo中,将Title属性的值复制为传进来的Value 的值,最终在ViewA界面上实现对Value的展示。

3、跳转

在导航接口中,不仅实现了打开前传入值,还有跳转前的操作方法,具体实现如下。

public class ViewAViewModel : IConfirmNavigationRequest
{
	public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
	{
		bool result = true;
		if(MessageBox.Show("确认导航?", "温馨提示", MessageBoxButton.YesNo) == MessageBoxResult.No)
		{
			result = false;
		}

		continuationCallback(result);
	}
	// 省略另外三个需要实现的方法
}

在以上示例中,将接口从INavigationAware改为了IConfirmNavigationRequest,实现ConfirmNavigationRequest方法来实现了跳转前的提示,并在提示框弹出后控制是否跳转。
IConfirmNavigationRequest接口继承自INavigationAware并且多了一个ConfirmNavigationRequest方法,故IConfirmNavigationRequest是兼容INavigationAware的。

4、日志

导航日志可以实现上一页、下一页等功能。返回上一页
返回下一页
如上图所示,可以看到D页面可以回到上一页,E页面可以回到下一页。

// MainWindowViewModel.cs 
IregionNavigationJournal journal;

private void GoForward()
{
	journal.GoForward();
}

private void GoBack()
{
	journal.GoBack();
}

private void OpenA()
{
	regionManager.RequestNavigate("ContentRegion", $"PageA?Value=Hello", arg =>
	{
		journal = arg.Context.NavigationService.Journal;
	});
}

private void OpenB()
{
	regionManager.RequestNavigate("ContentRegion", "ViewB", arg =>
	{
		journal = arg.Context.NavigationService.Journal;
	});
}

以上示例中,打开ViewA和ViewB之前都记录了日志,后面可以通过GoForward和GoBack方法,实现界面的前进和返回功能。

七、对话(Dialog)

在 Prism 框架中,对话(Dialog) 服务是一种用于管理和显示对话框的机制。这个服务允许你在应用程序中以一种声明式和松耦合的方式来显示对话框,并处理用户输入和交互。

// App.xaml.cs 
protected override void RegisterTypes(ICOntainerRegistry)
{
	containerRegistry.RegisterDialog<MsgView, MsgViewModel>("Question");
}

// MsgViewModel.cs
public class MsgViewModel : BindalbleBase, IDialogAware
{
	public MsgViewModel()
	{
		SaveCommand = new DelegateCommand(() =>
		{
			DialogParameters param = new DialogParameters();
			param.Add("Value", Title);
			RequestClose?.Invoke(new DialogResult(ButtonResult.OK, param));
		});
		CancelCommand = new DelegateCommand(() =>
		{
			RequestClose?.Invoke(new DialogResult(ButtonResult.No));
		});
	}

	public DelegateCommand SaveCommand { get; set; }
	public DelegateCommand CancelCommand { get; set; }
	
	private string _title;

	public string Title 
	{ 
		get { return _title; }
		set {_title = value; }
	}

	public event Action<IDialogResult> RequestClose;

	public bool CanCloseDialog()
	{
		return true;
	}

	public void OnDialogClosed()
	{
	}

	public void OnDialogOpened(IDialogParameters parameters)
	{
		var title = parameter.GetValue<string>("Value");
	}
}

// MainWindowViewModel.cs 
private void OpenA()
{
	DialogParameters param = new DialogParameters();
	param.Add("Value", "Test1");
	dialog.ShowDialog("Question", param, arg =>
	{
		if(arg.Result == ButtonResult.OK)
		{
			var vaule = arg.Parameters.GetValue<string>("Value");
			MessageBox.Show($"用户输入了:{value}");
		}
		else
		{
			MessageBox.Show("用户取消了弹窗");
		}
	});
}

以上示例中,实现对话需要先在App.xaml.cs里面注册一个对话框,并新建一个对话的ViewModel,实现对话逻辑,MsgViewModel类中主要是实现了保存和取消两个命令,保存命令实现将Title属性值取出并存入到param的Value属性里面,取消命令实现了弹窗的关闭。
主要通过OpenA中调用这个对话逻辑,当界面打开时,初始的Value赋值为Test1,即打开界面显示Test1,当输入内容后点击确认将弹窗提示输入内容,当取消或者关闭弹窗时将弹出取消弹窗的提示弹窗。

八、总结

Prism 是一个用于构建富客户端桌面和移动应用程序的框架,特别是在 .NET 平台上。它基于微软的模式与实践团队开发,并且是开源的。Prism 旨在简化应用程序的开发,特别是那些遵循 MVVM(Model-View-ViewModel)模式的应用程序。Prism 的目标是帮助开发者构建灵活、可维护和易于测试的应用程序。通过提供一套丰富的工具和模式,Prism 使得开发复杂的用户界面和业务逻辑变得更加简单和高效。

九、引用

B站 - WPF-Prism8.0核心教程

  • 18
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: WPF是一种基于XAML语言的用户界面开发框架,使开发人员能够轻松创建漂亮和高效的桌面应用程序。MVVM是一种模式,它在WPF应用程序中广泛使用,它提供了一种分离UI和业务逻辑的方式,从而简化了代码结构。Prism是一个开源框架,它基于MVVM模式和WPF框架,提供了一些技术和工具,使开发人员能够更轻松地构建复杂的WPF应用程序。 使用WPF MVVM Prism框架可以帮助开发人员提高应用程序的可维护性和可扩展性。通过MVVM,开发人员可以创建一个适应各种应用程序场景的模型,并将其与UI分离。数据绑定和命令绑定使开发人员能够更轻松地将模型中的数据和逻辑与UI控件集成起来。Prism框架还提供了一些工具和功能,如模块化应用程序开发、事件合器、导航、对话框、异常处理等功能。这些工具使开发人员能够更轻松地构建复杂的应用程序,并提供了一种可扩展和可重用的方法。 总之,使用WPF MVVM Prism可以使开发人员更轻松地构建复杂的应用程序,并提高应用程序的可维护性和可扩展性。开发人员可以根据自己的需求选择使用这个框架来开发WPF应用程序,从而提高他们的工作效率和代码质量。 ### 回答2: WPF MVVM Prism是一种基于Windows Presentation Foundation(WPF)的软件开发模式,采用了MVVM(Model-View-ViewModel)设计模式Prism框架来实现软件开发。MVVM是一种在WPF应用程序中使用的设计模式,它将应用程序的视图(View)与应用程序的模型(Model)分离开来,通过ViewModel来连接二者。Prism是一个帮助开发人员编写出复杂、可管控、可扩展和可维护的WPF应用程序的框架。 WPF MVVM Prism提供了很多好处:首先,它能实现软件的可重用性,通过将代码和视图分离,使得代码可以在多个不同的视图中重复使用,提高了开发效率。其次,它可以提高软件的可维护性,通过将逻辑和视图分离,确保逻辑代码与UI代码之间更少的耦合,提高了软件的可扩展性。此外,它还可以提高软件的可测试性,由于MVVM模式中将视图和逻辑分离开,所以开发人员可以更容易地编写出单元测试代码,来测试逻辑代码。最后,由于Prism框架提供了一些通用的,可定制的模块和服务,使得开发人员可以更快地实现常见功能、缩短开发时间。 总之,WPF MVVM Prism是一种高效、可扩展和易于维护的软件开发模式,它将视图和逻辑分离,提高了软件的可重用性和可测试性,同时也提高了软件的可扩展性和可复用性。 ### 回答3: WPF是一种桌面应用程序框架,它允许您为Windows创建高度交互式和可视化的应用程序界面。MVVM是一种软件编程模式,它将用户界面(UI)与业务逻辑分离,以便更好地实现可维护,可扩展和可组合的代码。Prism是一个WPF和Silverlight应用程序的组件库,它提供了一些可重用和可扩展的基础设施组件,帮助您更快速地构建、测试和维护WPF应用程序。因此,WPF MVVM Prism的组合可以帮助您更轻松高效地开发WPF应用程序。您可以使用MVVM模式来改进应用程序的结构和测试,使用Prism来更好地组织和可扩展您的代码,以及使用WPF来实现交互丰富的UI。同时还可以使用Prism提供的事件合器、导航器和模块化架构,实现更灵活的应用程序设计。WPF MVVM Prism的组合提供了一种更有效的方式来构建WPF应用程序,以满足现代用户体验的需求,并且更容易测试和维护,因此它已成为WPF应用程序开发的重要组合。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值