从0到1:使用Caliburn.Micro(WPF和MVVM)开发简单的计算器

这段时间一直在使用Caliburn.Micro这种应用了MVVM模式的WPF框架做开发,是时候总结一下了。

Caliburn.Micro(Caliburn.Micro框架概述 - https://blog.csdn.net/lzuacm/article/details/78886436) 是一个轻量级的WPF框架,简化了WPF中的不少用法,推荐做WPF开发时优先使用。

真正快速而熟练地掌握一门技术就可以尝试着用最快的速度去构建一个玩具项目(Toy project),然后不断地优化、重构之。比如本文将介绍如何使用Caliburn.Micro v3.2开发出一个简单的计算器,里面用到了C#中的async异步技术,Caliburn.Micro中的Conductor等等~

Step 1: 在VS中创建WPF项目

Step 2: 使用NuGet包管理工具为当前项目安装Caliburn.Micro
对于Caliburn.Micro 1.x和2.x版,只能使用.dll,需手动给项目加Reference。而3.0以后的版本可使用NuGet包管理工具来管理,安装和卸载既方便又彻底,推荐使用。(ps: NuGet之于Visual Studio(C++, C#等), 犹pip之于Python, npm之于node, maven之于Java, gem之于Ruby等等)

Step 3: 框架搭建

  1. 删除项目根目录下的MainWindow.xaml
  2. 按下图调整App.xaml
    删除语句StartupUri=”MainWindow.xmal”。
  3. 填充Application.Resources
    <Application.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><ResourceDictionary><local:Bootstrapper x:Key="bootstrapper"/></ResourceDictionary></ResourceDictionary.MergedDictionaries></ResourceDictionary></Application.Resources>

4 . 创建Bootstrapper类
然后让其继承自BootstrapperBase类,并加上构造函数,另外再重写函数OnStartup即可。

using System.Windows;
using Caliburn.Micro;
using CaliburnMicro_Calculator.ViewModels;namespace CaliburnMicro_Calculator
{public class Bootstrapper : BootstrapperBase{public Bootstrapper(){Initialize();}protected override void OnStartup(object obj, StartupEventArgs e){DisplayRootViewFor<ShellViewModel>();}}
}

5 . 在项目目录下新建Models, ViewModels, Views这3个文件夹
在ViewModel文件夹中添加ShellViewModel.cs,并创建Left, Right和Result这3个属性。

需要注意的是 ShellViewModel.cs需要继承类 Screen 和 INotifyPropertyChanged (用于感知并同步所绑定属性的变化),ShellViewModel具体代码为:

using System.ComponentModel;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using Caliburn.Micro;namespace CaliburnMicro_Calculator.ViewModels
{public class ShellViewModel : Screen, INotifyPropertyChanged{private double _left;private double _right;private double _result;public double Left{get { return _left; }set{_left = value;NotifyOfPropertyChange();}}public double Right{get { return _right; }set{_right = value;NotifyOfPropertyChange();}}public double Result{get { return _result; }set{_result = value;NotifyOfPropertyChange();}}
}

说明: 最开始布局xaml时,设计位置时采用的是左(operand 1), 中(operand 2), 右(result),于是属性值使用了Left, Right和Result。

Step 4: 设计XAML并绑定属性
在Views文件夹中创建Window,命名为ShellView.xaml,在Views文件夹下创建子文件夹Images,用于存放+,-,*,/这4种操作对应的小图标,其具体代码如下:

<Window x:Class="CaliburnMicro_Calculator.Views.ShellView"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:CaliburnMicro_Calculator.Views"xmlns:cal="http://www.caliburnproject.org"mc:Ignorable="d"Title="Calculator" SizeToContent="Height" Width="240"><StackPanel Background="Beige"><StackPanel Orientation="Horizontal"><Label Margin="10"Target="{Binding ElementName=left}">Operand _1:</Label><TextBox Margin="10"Width="72"x:Name="left"/></StackPanel><StackPanel Orientation="Horizontal"><Label Margin="10"Target="{Binding ElementName=right}">Operand _2:</Label><TextBox Margin="10"Width="72"x:Name="right"/></StackPanel><StackPanel Orientation="Horizontal"><Button Margin="10"x:Name="btnPlus" cal:Message.Attach="[Event Click]=[Action Plus(left.Text, right.Text):result.Text]"><Image Source="Images/op1.ICO"/></Button><Button Margin="10"x:Name="btnMinus" cal:Message.Attach="[Event Click]=[Action Minus(left.Text, right.Text):result.Text]"><Image Source="Images/op2.ICO"/></Button><Button Margin="10"x:Name="btnMultiply" cal:Message.Attach="[Event Click]=[Action Multipy(left.Text, right.Text):result.Text]"><Image Source="Images/op3.ICO"/></Button><Button Margin="10"x:Name="btnDivide" IsEnabled="{Binding Path=CanDivide}"cal:Message.Attach="[Event Click]=[Action Divide(left.Text, right.Text):result.Text]"><Image Source="Images/op4.ICO"/></Button></StackPanel><StackPanel Orientation="Horizontal"><Label Margin="10">Answer:</Label><TextBox Margin="10"Width="72"Text ="{Binding Path=Result, StringFormat={}{0:F4}}" IsReadOnly="True" /></StackPanel></StackPanel>
</Window>

说明:对操作数Operand _1和Operand _2,按Alt键+数字可以选中该处,这是WPF的一个特殊用法。由于计算结果不希望被修改,于是加上了属性IsReadOnly="True"

Step 5: 设计并绑定事件
由于暂时只打算实现+, -, *, /四种操作,于是我们只需创建相应的4个函数即可,由于除数是0这个操作不允许,于是需再加个判断函数CanDivide。

Caliburn.Micro中绑定事件的写法是:
cal:Message.Attach="[Event E]=[Action A]" (E是操作,比如Click, MouseDown, KeyDown等等,A是ViewModel中具体的函数。)

向ShellViewModel中加入事件中要做的事,此时ShellViewModel为:

using System.ComponentModel;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using Caliburn.Micro;namespace CaliburnMicro_Calculator.ViewModels
{public class ShellViewModel : Screen, INotifyPropertyChanged{private double _left;private double _right;private double _result;public double Left{get { return _left; }set{_left = value;NotifyOfPropertyChange();}}public double Right{get { return _right; }set{_right = value;NotifyOfPropertyChange();}}public double Result{get { return _result; }set{_result = value;NotifyOfPropertyChange();}}public bool CanDivide(double left, double right){return right != 0;}public async void Divide(double left, double right){Thread.Sleep(600);if (CanDivide(left, right) == true)Result = left / right;else MessageBox.Show("Divider cannot be zero.", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);}public async void Plus(double left, double right){Result = left + right;}public async void Minus(double left, double right){Result = left - right;}public async void Multipy(double left, double right){Result = left * right;}}
}

此时计算器的功能已基本完成,但我们可以对ViewModel进行适当的调整:
1.创建新的ViewModel - CalculatorViewModel,将原来的ShellViewModel中具体的计算逻辑移入到CalculatorViewModel中;
2.此时让ShellViewModel继承Conductor<Object>,于是ShellViewModel拥有了管理Screen实例的功能(ViewModel中使用ActivateItem函数,而View中使用X:Name=”ActivateItem”标签),其具体代码为:

using System.ComponentModel;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using Caliburn.Micro;namespace CaliburnMicro_Calculator.ViewModels
{public class ShellViewModel : Conductor<object>{public ShellViewModel(){}public void ShowCalculator(){ActivateItem(new CalculatorViewModel());}}
}

此时,CalculatorViewModel的具体代码为:

using System.ComponentModel;
using System.Threading;
using System.Windows;
using Caliburn.Micro;namespace CaliburnMicro_Calculator.ViewModels
{public class CalculatorViewModel: Screen, INotifyPropertyChanged{private double _left;private double _right;private double _result;public double Left{get { return _left; }set{_left = value;NotifyOfPropertyChange();}}public double Right{get { return _right; }set{_right = value;NotifyOfPropertyChange();}}public double Result{get { return _result; }set{_result = value;NotifyOfPropertyChange();}}public CalculatorViewModel(){}public bool CanDivide(double left, double right){return right != 0;}public async void Divide(double left, double right){Thread.Sleep(600);if (CanDivide(left, right) == true)Result = left / right;else MessageBox.Show("Divider cannot be zero.", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);}public async void Plus(double left, double right){Result = left + right;}public async void Minus(double left, double right){Result = left - right;}public async void Multipy(double left, double right){Result = left * right;}}
}

3 . 对于View,只需把CalculatorViewModel对应的CalculatorView作为ContentControl控件嵌入ShellView即可。此时ShellView的代码调整为:

<Window x:Class="CaliburnMicro_Calculator.Views.ShellView"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:CaliburnMicro_Calculator.Views"xmlns:cal="http://www.caliburnproject.org"mc:Ignorable="d"Title="Calculator" SizeToContent="Height" Width="240"><Grid MinHeight="200"><Button Content="Show Calculator" x:Name="ShowCalculator" Grid.Row="0"></Button><ContentControl x:Name="ActiveItem"></ContentControl>        </Grid>
</Window>

另外提一点,向ViewModel A中嵌入ViewModel B,一般来说需要做的操作是:
在A的view中使用ContentControl,绑定B的ViewModel只需使用语句cal:View.Model=”{Binding BViewModel}”即可,而B的view是UserControl就可以啦。

此时CalculatorView是一个UserControl,其代码为:

<UserControl x:Class="CaliburnMicro_Calculator.Views.CalculatorView"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:local="clr-namespace:CaliburnMicro_Calculator.Views"xmlns:cal="http://www.caliburnproject.org"mc:Ignorable="d"Width="240"><StackPanel Background="Beige"><StackPanel Orientation="Horizontal"><Label Margin="10"Target="{Binding ElementName=left}">Operand _1:</Label><TextBox Margin="10"Width="72"x:Name="left"/></StackPanel><StackPanel Orientation="Horizontal"><Label Margin="10"Target="{Binding ElementName=right}">Operand _2:</Label><TextBox Margin="10"Width="72"x:Name="right"/></StackPanel><StackPanel Orientation="Horizontal" HorizontalAlignment="Center"><Button Margin="10"x:Name="btnPlus" cal:Message.Attach="[Event Click]=[Action Plus(left.Text, right.Text):result.Text]"><Image Source="Images/op1.ICO"/></Button><Button Margin="10"x:Name="btnMinus" cal:Message.Attach="[Event Click]=[Action Minus(left.Text, right.Text):result.Text]"><Image Source="Images/op2.ICO"/></Button><Button Margin="10"x:Name="btnMultiply" cal:Message.Attach="[Event Click]=[Action Multipy(left.Text, right.Text):result.Text]"><Image Source="Images/op3.ICO"/></Button><Button Margin="10"x:Name="btnDivide" IsEnabled="{Binding Path=CanDivide}"cal:Message.Attach="[Event Click]=[Action Divide(left.Text, right.Text):result.Text]"><Image Source="Images/op4.ICO"/></Button></StackPanel><StackPanel Orientation="Horizontal"><Label Margin="10">Answer:</Label><TextBox Margin="10"Width="72"Text ="{Binding Path=Result, StringFormat={}{0:F4}, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="True" /></StackPanel></StackPanel>
</UserControl>

好啦,就酱,由于本例中逻辑并不复杂,Model暂时用不上,对于复杂一点的项目,Model主要负责数据的读取,如文件操作、数据库操作、service调用等,以后有机会举例具体来说。

如果需要持久化(persistent),则还需给给每对M-VM(Model和ViewModel)加入State,这个实际工程中也用得特别多。

Step 6: 功能举例
Calculator主页:

点击按钮“ShowCalculator”即可看到具体的计算器~

乘法举例:

除法举例:

最后附上代码:
CaliburnMicro-Calculator: A simple Calculator using Caliburn.Micro
https://github.com/yanglr/CaliburnMicro-Calculator,
欢迎fork和star,如有改进意见欢迎提交pull request~

从0到1:使用Caliburn.Micro(WPF和MVVM)开发简单的计算器相关推荐

  1. WPF框架教程 | 从0到1:使用Caliburn.Micro(WPF和MVVM)开发简单的计算器

    之前时间一直在使用Caliburn.Micro这种应用了MVVM模式的WPF框架做开发,是时候总结一下了. Caliburn.Micro(https://blog.csdn.net/lzuacm/ar ...

  2. WPF 用 AvalonEdit 开发简单的代码编辑器 支持高亮自动提示

    用 WPF 开发一个代码编辑器的难度很低,因为行业里面有很多小伙伴开发过,这些小伙伴将自己的代码开源了,发布到 NuGet 上,所以让我开发一个代码编辑器的难度实在太低.在不要有奇特的要求情况下,通过 ...

  3. C# WPF MVVM开发框架Caliburn.Micro 关于Conventions⑧

    01 - 关于Conventions Caliburn.Micro的一个主要特性是,它能够通过一系列约定消除对锅炉铭牌代码的需求.有些人喜欢习俗,有些人讨厌习俗.这就是为什么CM的约定是完全可定制的, ...

  4. C# WPF MVVM开发框架Caliburn.Micro自定义引导程序④

    01 - 自定义引导程序 在上一部分中,我们讨论了Caliburn.Micro WPF应用程序的最基本配置,并演示了与操作和约定相关的两个简单功能.在这一部分中,我想进一步探讨Bootstrapper ...

  5. 【愚公系列】2023年02月 .NET CORE工具案例-Caliburn.Micro的使用基于WPF的改造的MVVM案例

    文章目录 前言 1.Caliburn.Micro是什么 2.Caliburn.Micro的主要功能 一.Caliburn.Micro的使用基于WPF的改造 1.项目介绍 2.安装软件包 3.改造App ...

  6. C# WPF MVVM开发框架Caliburn.Micro Screens, Conductors 和 Composition⑦

    01 - Screens, Conductors and Composition Actions, Coroutines and Conventions往往最能吸引Caliburn.Micro的注意力 ...

  7. C# WPF MVVM开发框架Caliburn.Micro快速搭建③

    01 - 启动项目 打开Visual Studio 创建一个名为"Caliburn.Micro.Hello"的新WPF应用程序 添加对Caliburn.Micro Nuget包的引 ...

  8. C# WPF MVVM开发框架Caliburn.Micro 自定义Conventions⑩

    处理自定义约定 虽然ViewLocator和ViewModelLocator类通过提供对每个类的NameTransformer实例的公共访问来支持非标准约定,但对于那些不熟悉正则表达式语法的人来说,添 ...

  9. C# WPF Caliburn.Micro框架下利用Mef加载其它项目界面

    01 - 前言 MEF是微软自家的托管可扩展框架,在这里我把它用成了ioc容器.在Caliburn.Micro框架下,view和viewmodel被注入到CompositionContainer容器中 ...

最新文章

  1. 剑指offer:左旋转字符串
  2. day01_03.人人都会编程
  3. 用cn.hutool工具包进行图片上传下载示例
  4. 数据结构(六)---队列的链式存储的实现---java版
  5. 二分查找法的循环与递归实现及时间复杂度分析
  6. mysql创建索引语句
  7. sql server 2012远程链接的方法及步骤
  8. 汇编程序中,字符数据和ASCII的对应关系
  9. 从键盘上录入学生人数和每个学生的分数,按分数降序输出所有的分数,java冒泡排序应用
  10. flask数据库sqlalchemy查询
  11. mysql定时备份脚本
  12. 小程序云函数实现微信支付如此简单
  13. 微信小程序跳转美团饿了么指定商家
  14. Java的11个关键术语
  15. vtk中画几何图形存储为vtk文件并在窗口显示
  16. Python金融应用编程(数据分析、定价与量化投资) !
  17. cvReleaseCapture函数说明
  18. JavaWeb-学生宿舍管理系统
  19. SQL注入漏洞测试(报错盲注)笔记
  20. LCD Keypad Shield

热门文章

  1. python 矩阵操作
  2. Echarts绘图技术总结
  3. 百度翻译自定义其它语种翻译为中文
  4. Windows安装npm淘宝镜像npm ERR! errno -4048 npm ERR! code EPERM npm ERR! syscall unlink
  5. 银行业务流程自动化-银行业RPA机器人流程自动化解决方案
  6. Oracle 日期格式yyyy/m/d 的字符串变成 yyyy-mm-dd
  7. linux上mysql5.7忘记密码,Linux下Mysql5.7忘记密码
  8. 手把手教你实现『B站直播』弹幕实时分析
  9. Android 源码编译 及 mk文件解读
  10. C 函数被调用时发生了什么:过程活动记录