当前位置:   article > 正文

C# WPF MVVM模式[经典]案例

wpf,基于mvvm 模式开发的tcp 服务器

01

前言

        Caliburn.Micro(简称CM)一经推出便备受推崇,作为一款MVVM开发模式的经典框架,越来越多的受到wpf开发者的青睐.我们看一下官方的描述:Caliburn是一个为Xaml平台设计的小型但功能强大的框架。Micro实现了各种UI模式,用于解决实际问题。突出显示的模式包括MVVM(表示模型)、MVP和MVC。目前CM框架还不不停的开发和迭代中,目前最新版本4.0.212,推出于2022年8月27日,已经可以支持.NET7。

02


项目介绍

解决方案由四个项目组成:见下图

12f290f5563a78d49790a7d72b5f8c1c.png

HelloWorld:框架的搭建、容器注入相关;

HelloWorld.Core;放置数据模型,即mvvm中的M;

HelloWorld.ViewModels:模型视图,即VM;

HelloWorld.Views:V,即视图.

项目基于.NET5开发:

fec91cd0db9e38dea82c179b36bdc5ee.png

CM框架版本:4.0.212;

运行结果显示:

a8473961e6e6f7af630a19eaa80b61db.png

03


代码展示和讲解

① 首先是HelloWorld讲解,这里启动代码:Startup.CS

  1. public class Startup : BootstrapperBase
  2. {
  3. SimpleContainer _container;
  4. public Startup()
  5. {
  6. Initialize();
  7. }
  8. protected override void Configure()
  9. {
  10. _container = new SimpleContainer()
  11. .Singleton<IWindowManager, WindowManager>()
  12. .Singleton<IEventAggregator, EventAggregator>();
  13. foreach (var asm in SelectAssemblies())
  14. {
  15. foreach (var vm in asm.GetTypes())
  16. {
  17. if (vm.Name.EndsWith("VM"))
  18. {
  19. _container.RegisterPerRequest(vm, null, vm);
  20. }
  21. }
  22. }
  23. var myRule = new TypeMappingConfiguration
  24. {
  25. ViewModelSuffix = "VM",
  26. ViewSuffixList = new() { "" }
  27. };
  28. ViewLocator.ConfigureTypeMappings(myRule);
  29. ViewModelLocator.ConfigureTypeMappings(myRule);
  30. }
  31. protected override void OnStartup(object sender, StartupEventArgs e)
  32. {
  33. base.OnStartup(sender, e);
  34. DisplayRootViewForAsync<IndexVM>();
  35. }
  36. protected override IEnumerable<Assembly> SelectAssemblies()
  37. {
  38. return new List<Assembly>
  39. {
  40. Assembly.Load("HelloWorld"),
  41. Assembly.Load("HelloWorld.Views"),
  42. Assembly.Load("HelloWorld.ViewModels"),
  43. };
  44. }
  45. protected override object GetInstance(Type service, string key)
  46. {
  47. return _container.GetInstance(service, key);
  48. }
  49. }

这里容器采用了CM自带的SimpleContainer:

开始先把窗口管理器和事件聚合器注册到了容器中:

  1. _container = new SimpleContainer()
  2. .Singleton<IWindowManager, WindowManager>()
  3. .Singleton<IEventAggregator, EventAggregator>();

然后通过反射把下面三个程序集:

  1. Assembly.Load("HelloWorld"),
  2. Assembly.Load("HelloWorld.Views"),
  3. Assembly.Load("HelloWorld.ViewModels"),

中vm结尾的视图模型文件注册到容器:

  1. foreach (var asm in SelectAssemblies())
  2. {
  3. foreach (var vm in asm.GetTypes())
  4. {
  5. if (vm.Name.EndsWith("VM"))
  6. {
  7. _container.RegisterPerRequest(vm, null, vm);
  8. }
  9. }
  10. }

接下来是自定义了一套CM的VM和V的匹配规则,默认情况,CM的匹配规则是视图以View结尾,视图模型以ViewModel结尾,这里的规则是VM以VM结尾,View只要前缀和Viewmodel的一致就可以:

  1. var myRule = new TypeMappingConfiguration
  2. {
  3. ViewModelSuffix = "VM",
  4. ViewSuffixList = new() { "" }
  5. };
  6. ViewLocator.ConfigureTypeMappings(myRule);
  7. ViewModelLocator.ConfigureTypeMappings(myRule);

②HelloWorld.Views,这里放的是视图,代码很简单,不展开了,比较新颖的用法是它通过load函数接在view的:

cal:Message.Attach="[Event Loaded]=[Loaded($view,$eventArgs)]"
  1. public void Loaded(UserControl control, RoutedEventArgs @event)
  2. {
  3. Debug.WriteLine(control);
  4. Debug.WriteLine(@event);
  5. }

③ HelloWorld.ViewModels,视图模型:

LoginVM.cs这是登录窗体的后台逻辑:点击登录后发送背景线程异步事件更新进度条:

  1. public async Task DoLogin()
  2. {
  3. await _eventAggregator.PublishOnBackgroundThreadAsync(new BusyMessage(true));
  4. await Task.Delay(1000);
  5. MessageBox.Show("Test Login Success");
  6. await _eventAggregator.PublishOnBackgroundThreadAsync(new BusyMessage(false));
  7. }

IndexVM.cs:继承IHandle<BusyMessage>,

接收事件更新进度条:

  1. public Task HandleAsync(BusyMessage message, CancellationToken cancellationToken)
  2. {
  3. if (message.IsBusy)
  4. {
  5. BarValue = 50;
  6. }
  7. else
  8. {
  9. BarValue = 0;
  10. }
  11. return Task.CompletedTask;
  12. }

通过ioc容器获取VM:

 public LoginVM LoginVM { get; set; } = IoC.Get<LoginVM>();

  1. public LoginVM LoginVM { get; set; } = IoC.Get<LoginVM>();
  2. public TableVM TableVM { get; set; } = IoC.Get<TableVM>();

TableVM.cs:

数据集合定义:  public ObservableCollection<Foo> Data { get; set; }

开线程更新集合数据:用 await Task.Delay(1000);演示一秒

  1. Task.Run(async () =>
  2. {
  3. while (true)
  4. {
  5. if (IsShow)
  6. {
  7. _data.Add(new Foo
  8. {
  9. Id = Guid.NewGuid(),
  10. Name = "John" + new Random().Next(1, 100),
  11. School = "上海大学"
  12. });
  13. Data = new ObservableCollection<Foo>(_data);
  14. }
  15. await Task.Delay(1000);
  16. }
  17. });

 [AddINotifyPropertyChangedInterface]:来源于,可以自动通知界面数据更新。

049ca8ee3eb9606d15dfe5c80e3a374f.png

04


源码下载及声明

声明:首先感谢群友提供源码,需要和源码提供者本人直面交流的可以通过邮箱:xingrui_zhuang@asiasymbol.com 联系.

  1. 源码百度网盘链接
  2. 链接:https://pan.baidu.com/s/1BHkVEFWHwGQf6EwHpWCBKw
  3. 提取码:6666
  4. 技术群:添加小编微信并备注进群
  5. 小编微信:mm1552923
  6. 公众号:dotNet编程大全
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/711084
推荐阅读
相关标签
  

闽ICP备14008679号