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和Pyecharts创建交互式地图

《使用Python和Pyecharts创建交互式地图》在数据可视化领域,创建交互式地图是一种强大的方式,可以使受众能够以引人入胜且信息丰富的方式探索地理数据,下面我们看看如何使用Python和Pyec... 目录简介Pyecharts 简介创建上海地图代码说明运行结果总结简介在数据可视化领域,创建交互式地

Java Stream流使用案例深入详解

《JavaStream流使用案例深入详解》:本文主要介绍JavaStream流使用案例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录前言1. Lambda1.1 语法1.2 没参数只有一条语句或者多条语句1.3 一个参数只有一条语句或者多

Java Spring 中 @PostConstruct 注解使用原理及常见场景

《JavaSpring中@PostConstruct注解使用原理及常见场景》在JavaSpring中,@PostConstruct注解是一个非常实用的功能,它允许开发者在Spring容器完全初... 目录一、@PostConstruct 注解概述二、@PostConstruct 注解的基本使用2.1 基本代

C#使用StackExchange.Redis实现分布式锁的两种方式介绍

《C#使用StackExchange.Redis实现分布式锁的两种方式介绍》分布式锁在集群的架构中发挥着重要的作用,:本文主要介绍C#使用StackExchange.Redis实现分布式锁的... 目录自定义分布式锁获取锁释放锁自动续期StackExchange.Redis分布式锁获取锁释放锁自动续期分布式

springboot使用Scheduling实现动态增删启停定时任务教程

《springboot使用Scheduling实现动态增删启停定时任务教程》:本文主要介绍springboot使用Scheduling实现动态增删启停定时任务教程,具有很好的参考价值,希望对大家有... 目录1、配置定时任务需要的线程池2、创建ScheduledFuture的包装类3、注册定时任务,增加、删

使用Python实现矢量路径的压缩、解压与可视化

《使用Python实现矢量路径的压缩、解压与可视化》在图形设计和Web开发中,矢量路径数据的高效存储与传输至关重要,本文将通过一个Python示例,展示如何将复杂的矢量路径命令序列压缩为JSON格式,... 目录引言核心功能概述1. 路径命令解析2. 路径数据压缩3. 路径数据解压4. 可视化代码实现详解1

Pandas透视表(Pivot Table)的具体使用

《Pandas透视表(PivotTable)的具体使用》透视表用于在数据分析和处理过程中进行数据重塑和汇总,本文就来介绍一下Pandas透视表(PivotTable)的具体使用,感兴趣的可以了解一下... 目录前言什么是透视表?使用步骤1. 引入必要的库2. 读取数据3. 创建透视表4. 查看透视表总结前言

Python 交互式可视化的利器Bokeh的使用

《Python交互式可视化的利器Bokeh的使用》Bokeh是一个专注于Web端交互式数据可视化的Python库,本文主要介绍了Python交互式可视化的利器Bokeh的使用,具有一定的参考价值,感... 目录1. Bokeh 简介1.1 为什么选择 Bokeh1.2 安装与环境配置2. Bokeh 基础2

Android使用ImageView.ScaleType实现图片的缩放与裁剪功能

《Android使用ImageView.ScaleType实现图片的缩放与裁剪功能》ImageView是最常用的控件之一,它用于展示各种类型的图片,为了能够根据需求调整图片的显示效果,Android提... 目录什么是 ImageView.ScaleType?FIT_XYFIT_STARTFIT_CENTE

Java学习手册之Filter和Listener使用方法

《Java学习手册之Filter和Listener使用方法》:本文主要介绍Java学习手册之Filter和Listener使用方法的相关资料,Filter是一种拦截器,可以在请求到达Servl... 目录一、Filter(过滤器)1. Filter 的工作原理2. Filter 的配置与使用二、Listen