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

2023-11-06 12:32

本文主要是介绍WPF框架教程 | 从0到1:使用Caliburn.Micro(WPF和MVVM)开发简单的计算器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

640?wx_fmt=gif

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

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

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


>>>1.在VS中创建WPF项目<<<

640?

640?wx_fmt=png


>>>2.使用NuGet包管理工具为当前项目安装Caliburn.Micro <<<

640?

对于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等等)

640?wx_fmt=png


>>>3.框架搭建  <  <  <

640?
  1. 删除项目根目录下的MainWindow.xaml

  2. 按下图调整 App.xaml
    删除语句

    StartupUri="MainWindow.xmal"。

    640?wx_fmt=png

  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。


>>>4.设计XAML并绑定属性 <   <  <

640?

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


>>>5.设计并绑定事件  <  <  <

640?

由于暂时只打算实现+, -, *, /四种操作,于是我们只需创建相应的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,这个实际工程中也用得特别多。


>>>6.功能举例  <  <  <

640?

Calculator主页:
640?wx_fmt=png

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

乘法举例:
640?wx_fmt=png

除法举例:
640?wx_fmt=png


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



640?wx_fmt=gif


原文地址:

https://blog.csdn.net/lzuacm/article/details/80559517

 

更多精彩文章,欢迎访问本人博客https://enjoy233.cnblogs.com 或 知乎搜索Bravo Yeung.

欢迎转发到朋友圈,公众号转载请后台联系本人申请授权~



推荐阅读

中英文电子书下载网站大搜罗

英语语法工具 | 那些可以纠正英语文章中语法的神器们

开发者见闻 | ASP.NET Core开发者路线图



smiley_66.png点击在看的人,

2019都会变得特别好看

这篇关于WPF框架教程 | 从0到1:使用Caliburn.Micro(WPF和MVVM)开发简单的计算器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/356654

相关文章

使用Python和OpenCV库实现实时颜色识别系统

《使用Python和OpenCV库实现实时颜色识别系统》:本文主要介绍使用Python和OpenCV库实现的实时颜色识别系统,这个系统能够通过摄像头捕捉视频流,并在视频中指定区域内识别主要颜色(红... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间详解

Windows下C++使用SQLitede的操作过程

《Windows下C++使用SQLitede的操作过程》本文介绍了Windows下C++使用SQLite的安装配置、CppSQLite库封装优势、核心功能(如数据库连接、事务管理)、跨平台支持及性能优... 目录Windows下C++使用SQLite1、安装2、代码示例CppSQLite:C++轻松操作SQ

Python常用命令提示符使用方法详解

《Python常用命令提示符使用方法详解》在学习python的过程中,我们需要用到命令提示符(CMD)进行环境的配置,:本文主要介绍Python常用命令提示符使用方法的相关资料,文中通过代码介绍的... 目录一、python环境基础命令【Windows】1、检查Python是否安装2、 查看Python的安

Python并行处理实战之如何使用ProcessPoolExecutor加速计算

《Python并行处理实战之如何使用ProcessPoolExecutor加速计算》Python提供了多种并行处理的方式,其中concurrent.futures模块的ProcessPoolExecu... 目录简介完整代码示例代码解释1. 导入必要的模块2. 定义处理函数3. 主函数4. 生成数字列表5.

Python中help()和dir()函数的使用

《Python中help()和dir()函数的使用》我们经常需要查看某个对象(如模块、类、函数等)的属性和方法,Python提供了两个内置函数help()和dir(),它们可以帮助我们快速了解代... 目录1. 引言2. help() 函数2.1 作用2.2 使用方法2.3 示例(1) 查看内置函数的帮助(

Linux脚本(shell)的使用方式

《Linux脚本(shell)的使用方式》:本文主要介绍Linux脚本(shell)的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述语法详解数学运算表达式Shell变量变量分类环境变量Shell内部变量自定义变量:定义、赋值自定义变量:引用、修改、删

Python实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部

Java使用HttpClient实现图片下载与本地保存功能

《Java使用HttpClient实现图片下载与本地保存功能》在当今数字化时代,网络资源的获取与处理已成为软件开发中的常见需求,其中,图片作为网络上最常见的资源之一,其下载与保存功能在许多应用场景中都... 目录引言一、Apache HttpClient简介二、技术栈与环境准备三、实现图片下载与保存功能1.

Python中使用uv创建环境及原理举例详解

《Python中使用uv创建环境及原理举例详解》uv是Astral团队开发的高性能Python工具,整合包管理、虚拟环境、Python版本控制等功能,:本文主要介绍Python中使用uv创建环境及... 目录一、uv工具简介核心特点:二、安装uv1. 通过pip安装2. 通过脚本安装验证安装:配置镜像源(可

LiteFlow轻量级工作流引擎使用示例详解

《LiteFlow轻量级工作流引擎使用示例详解》:本文主要介绍LiteFlow是一个灵活、简洁且轻量的工作流引擎,适合用于中小型项目和微服务架构中的流程编排,本文给大家介绍LiteFlow轻量级工... 目录1. LiteFlow 主要特点2. 工作流定义方式3. LiteFlow 流程示例4. LiteF