当前位置:   article > 正文

【.NET6+WPF】WPF使用prism框架+Unity IOC容器实现MVVM双向绑定和依赖注入

prism 视图注入

前言:在C/S架构上,WPF无疑已经是“桌面一霸”了。在.NET生态环境中,很多小伙伴还在使用Winform开发C/S架构的桌面应用。但是WPF也有很多年的历史了,并且基于MVVM的开发模式,受到了很多开发者的喜爱。

并且随着工业化的进展,以及几年前微软对.NET平台的开源,国内大多数企业的工业系统或上位机系统,也慢慢从使用MFC、QT等C++平台,转向了.NET平台。并且.NET平台上,桌面应用上,WPF由于其独特的一些特性、以及可以制作动画、无损图像等,WPF的占比也越来越高。但是大多数小伙伴可能还是按照开发Winform的传统思路来开发WPF,所以这篇文章当做是一个使用MVVM模式开发的入门教程,希望大家在开发WPF的过程中,可以享受MVVM双向绑定的快乐。

本篇文章有关环境说明:

开发环境:VS 2022企业版

.NET版本环境:.NET 6

开发的操作系统环境:Win 10

1、先创建一个WPF应用程序,环境选择.NET 6

aeef3c92dc75b49357bc2aee726d5896.png

2、创建完成以后,如下图所示。

654d8723b5934f396dd612d0aaef8156.png

3、再新建一个WPF类库项目,用于存放所有第三方nuget包。此处纯个人习惯,用于防止多项目引用包的时候,产生包版本不一致的问题。

e2fa406f5e045ee965cbd0f393573008.png

4、包项目里面,添加三个核心的包。分别是:Prism.Unity 、   Prism.Unity.Extensions   和  Unity.Microsoft.DependencyInjection  

其中,Prism.Unity 、   Prism.Unity.Extensions  用于提供基础的Prism框架有关的环境以及Unity容器。Unity.Microsoft.DependencyInjection  用于提供可支持属性注入的方式,如果不使用属性注入,也可以不使用。

cc5358c87c0d04658441d574449d975f.png

5、WpfDemo项目里面,引用刚刚的包项目后,修改App.xaml文件里面的默认配置项。以下是默认的内容:

42a6d9839313bfe6cf59adf2f4a2c207.png

6、替换为以下的内容。以下内容代表的是该程序引入prism框架。

0605fa0fdaf85b08e5ee5d592ff27c77.png

7、App.cs类里面,继承改为PrismApplication,并且提供几个方法的重写。如果没有重写,可能会提示错误。

7fe415dd67a0ca93e8bf52bfa43ef551.png

8、都载入以后,运行程序,就可以启动画面了。

1628585db68db3805d693aa13e7c89c0.png

9、项目新建Views文件夹和ViewModels文件夹。prism框架默认会自动识别存在Views文件夹的为视图端,ViewModels文件夹为VM端,用于自动双向绑定的匹配使用。

并且VM类与Views视图必须名称对应,VM类的结尾必须是xxxViewModel。

先建立一个登录页面,存放于Views文件夹下,然后页面引入prism框架所需的目录,如图所示。

同时设置了一个页面名称,该名称后面当做参数进行传递使用。

d4ee4711dfa2898eeb46da535dfb87bd.png

10、新建对应Login窗体的VM类 LoginViewModel,并且继承BindbleBase类,用于提供prism的双向绑定功能。

4dcf4e18d255752b438719b34f50de1c.png

11、提供用户名、密码属性,以及用于按钮触发的事件属性。并且提供了一个模拟用户登录的方法。

eae67d4d9251b861ccbf8aff97bab3c0.png

12、在Login.xaml文件下,新增两个输入框和一个按钮,用于模拟用户登录功能和双向绑定功能。Mode=TwoWay的意思是,前端数据变更,会自动同步到后端绑定的属性上;后端绑定的属性如果被修改值了,也会传递到前端进行同步显示。还有其他的Mode,小伙伴们可以自行去尝试。

Command命令用于绑定事件属性,并且提供了一个参数,把当前页面当做参数传入进去,用于页面跳转使用;如果不需要参数的情况下,直接不需要CommandParameter属性就行。Command命令默认是鼠标单击事件,如果是其他事件需要实现,可以自定义做一些对应的事件的封装来进行实现。

其他说明:任意属性都是可以通过双向绑定进行实现的,包括控件名称、以下label控件的content属性、其他属性等等一系列。大佬们可以自行玩玩,此处提供简单案例,所以只对输入框的Text属性和按钮的点击事件提供了双向绑定的功能。

315ae9b366a6d127e0644d637da32980.png

13、在App.cs类里面,提供InitializeShell方法的重写,并且注册Login页面。此处可以实现启动时候打开登录页面,通过提供DialogResult属性以后,就可以打开CreateShell方法里面注册的页面了。

d4e50ce7412a9258e29a6af837e49d61.png

14、现在运行程序,打开了登录页面,进行验证一下,如下图所示,说明验证生效了。输入正确的用户名和密码就可以进入到MainWindow页面。

9d7ed5ca13906b46b82f5560f21dcf12.png

15、接下来试试依赖注入的使用。先创建一个WPF类库项目,提供一个LoginService类与接口当做服务;并提供UserLogin方法的实现,如下图所示。

8cf7c6730766e7e27dcd344979ad4bf3.png

16、项目引用以后,提供属性注入。属性注入需要使用public,并且是属性,以及添加 Dependency的标记;如果是构造函数注入,则无需这些步骤。然后在登录方法里面,提供注入方法的使用,如下图所示。

30b5ce2820796f8779b94e78bf616d49.png

17、在App.cs类里面,先前提供的重写方法 RegisterTypes方法里面,进行服务的注册。

以下提供了一个瞬时生命周期的注入,如下所示。如果要使用其他生命周期,大佬们可以自行研究,都是自带的,我就不多写了。

458e034f96935490a338dc58e1ee2240.png

18、最后,运行程序,查看效果,程序运行符合预期,说明使用unity ioc容器进行服务注册成功。

bb78ef7d1f4f17e942c4a8425f041a2d.png

19、 后记——有关代码奉上:

App.xaml 

6cace8d13f79fd12e1aa2159a3d0dc86.jpeg

  1. <prism:PrismApplication x:Class="WpfDemo.App"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:local="clr-namespace:WpfDemo"
  5. xmlns:prism="http://prismlibrary.com/">
  6. <Application.Resources>
  7. </Application.Resources>
  8. </prism:PrismApplication>

f74b7c04778c239669769df06e770846.jpeg

App.cs

240f6dde5e600eb763c0e7e82df9e704.jpeg

  1. public partial class App : PrismApplication // Application { public App() { } protected override Window CreateShell()
  2. { return Container.Resolve<MainWindow>();
  3. } protected override void InitializeShell(Window shell)
  4. { if (Container.Resolve<Login>().ShowDialog() == false)
  5. {
  6. Application.Current?.Shutdown();
  7. } else
  8. { base.InitializeShell(shell);
  9. }
  10. } protected override void RegisterTypes(IContainerRegistry containerRegistry)
  11. {
  12. containerRegistry.Register<ILoginService, LoginService>(); // 默认是transient注册
  13. } protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
  14. {
  15. }

175bbe44cc44b52003a2f97141edb043.jpeg

LoginViewModel.cs

308a3551e3aee1049bb18824813b1953.jpeg

  1. public class LoginViewModel: BindableBase
  2. {
  3. [Dependency] // using Unity;
  4. public ILoginService _loginService { get; set; } private string userName=""; private string password=""; public string UserName
  5. { get { return userName; } set { SetProperty(ref userName, value); }
  6. } public string Password
  7. { get { return password; } set { SetProperty(ref password, value); }
  8. }
  9. ICommand? loginCommand; public ICommand LoginCommand { get
  10. { if (loginCommand == null)
  11. {
  12. loginCommand = new DelegateCommand<object>(UserLogin);
  13. } return loginCommand;
  14. }
  15. } void UserLogin(object obj)
  16. { if(!_loginService.UserLogin(this.UserName,this.Password))
  17. {
  18. MessageBox.Show("用户名或密码错误"); return;
  19. }
  20. (obj as Window).DialogResult = true;
  21. }
  22. }

d04b8ae27bf8964c31e60b79b77381d7.jpeg

Login.xaml

52946957a12d746ede44389cae0edee4.jpeg

  1. <Window x:Class="WpfDemo.Views.Login"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6. xmlns:local="clr-namespace:WpfDemo.Views"
  7. xmlns:prism="http://prismlibrary.com/"
  8. prism:ViewModelLocator.AutoWireViewModel="True"
  9. mc:Ignorable="d" Name="loginWindow"
  10. Title="Login" Height="400" Width="600">
  11. <Grid>
  12. <Label Content="用户名" HorizontalAlignment="Left" Margin="56,119,0,0" VerticalAlignment="Top"/>
  13. <Label Content="密码" HorizontalAlignment="Left" Margin="65,150,0,0" VerticalAlignment="Top"/>
  14. <TextBox HorizontalAlignment="Left" Margin="112,124,0,0" TextWrapping="Wrap"
  15. Text="{Binding UserName,Mode=TwoWay}" VerticalAlignment="Top" Width="143"/>
  16. <TextBox HorizontalAlignment="Left" Margin="112,154,0,0" TextWrapping="Wrap"
  17. Text="{Binding Password,Mode=TwoWay}" VerticalAlignment="Top" Width="143"/>
  18. <Button Content="登录" HorizontalAlignment="Left" Margin="166,192,0,0"
  19. Command="{Binding LoginCommand}" CommandParameter="{Binding ElementName=loginWindow}"
  20. VerticalAlignment="Top" Height="24" Width="89"/>
  21. </Grid>
  22. </Window>

2dc91e024aed3d143c94e592a4359b57.jpeg

LoginService.cs

6a40f58981ed73a1d643d75d18dc90ba.jpeg

  1. public class LoginService: ILoginService
  2. { public Boolean UserLogin(string userName, string password) { if(userName =="wesky" && password == "123456")
  3. { return true;
  4. } else
  5. { return false;
  6. }
  7. }
  8. }

dda3e4d5c33f140aa4ff18e57f83afad.jpeg

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号