WPF框架教程 | 从0到1:使用Caliburn.Micro(WPF和MVVM)开发简单的计算器
之前時(shí)間一直在使用Caliburn.Micro這種應(yīng)用了MVVM模式的WPF框架做開發(fā),是時(shí)候總結(jié)一下了。
Caliburn.Micro(https://blog.csdn.net/lzuacm/article/details/78886436)是一個(gè)輕量級(jí)的WPF框架,簡(jiǎn)化了WPF中的不少用法,推薦做WPF開發(fā)時(shí)優(yōu)先使用。
真正快速而熟練地掌握一門技術(shù)就可以嘗試著用最快的速度去構(gòu)建一個(gè)玩具項(xiàng)目(Toy project),然后不斷地優(yōu)化、重構(gòu)之。比如本文將介紹如何使用Caliburn.Micro v3.2開發(fā)出一個(gè)簡(jiǎn)單的計(jì)算器,里面用到了C#中的async異步技術(shù),Caliburn.Micro中的Conductor等等~
>>>1.在VS中創(chuàng)建WPF項(xiàng)目<<<
>>>2.使用NuGet包管理工具為當(dāng)前項(xiàng)目安裝Caliburn.Micro?<<<
對(duì)于Caliburn.Micro 1.x和2.x版,只能使用.dll,需手動(dòng)給項(xiàng)目加Reference。而3.0以后的版本可使用NuGet包管理工具來管理,安裝和卸載既方便又徹底,推薦使用。(ps: NuGet之于Visual Studio(C++, C#等), 猶pip之于Python, npm之于node, maven之于Java, gem之于Ruby等等)
>>>3.框架搭建? <? <? <
刪除項(xiàng)目根目錄下的MainWindow.xaml
按下圖調(diào)整 App.xaml
刪除語(yǔ)句
StartupUri="MainWindow.xmal"。
填充Application.Resources
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<local:Bootstrapper x:Key="bootstrapper"/>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
?? 4 . 創(chuàng)建Bootstrapper類
然后讓其繼承自BootstrapperBase類,并加上構(gòu)造函數(shù),另外再重寫函數(shù)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 . 在項(xiàng)目目錄下新建Models, ViewModels, Views這3個(gè)文件夾
在ViewModel文件夾中添加ShellViewModel.cs,并創(chuàng)建Left, Right和Result這3個(gè)屬性。
需要注意的是 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時(shí),設(shè)計(jì)位置時(shí)采用的是左(operand 1), 中(operand 2), 右(result),于是屬性值使用了Left, Right和Result。
>>>4.設(shè)計(jì)XAML并綁定屬性?<? ?<? <
在Views文件夾中創(chuàng)建Window,命名為ShellView.xaml,在Views文件夾下創(chuàng)建子文件夾Images,用于存放+,-,*,/這4種操作對(duì)應(yīng)的小圖標(biāo),其具體代碼如下:
<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>
說明:對(duì)操作數(shù)Operand _1和Operand _2,按Alt鍵+數(shù)字可以選中該處,這是WPF的一個(gè)特殊用法。由于計(jì)算結(jié)果不希望被修改,于是加上了屬性IsReadOnly="True"。
>>>5.設(shè)計(jì)并綁定事件??<? <? <
由于暫時(shí)只打算實(shí)現(xiàn)+, -, *, /四種操作,于是我們只需創(chuàng)建相應(yīng)的4個(gè)函數(shù)即可,由于除數(shù)是0這個(gè)操作不允許,于是需再加個(gè)判斷函數(shù)CanDivide。
Caliburn.Micro中綁定事件的寫法是:
cal:Message.Attach="[Event E]=[Action A]"
(E是操作,比如Click, MouseDown, KeyDown等等,A是ViewModel中具體的函數(shù)。)
向ShellViewModel中加入事件中要做的事,此時(shí)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;
}
}
}
此時(shí)計(jì)算器的功能已基本完成,但我們可以對(duì)ViewModel進(jìn)行適當(dāng)?shù)恼{(diào)整:
1.創(chuàng)建新的ViewModel - CalculatorViewModel,將原來的ShellViewModel中具體的計(jì)算邏輯移入到CalculatorViewModel中;
2.此時(shí)讓ShellViewModel繼承Conductor<Object>,于是ShellViewModel擁有了管理Screen實(shí)例的功能(ViewModel中使用ActivateItem函數(shù),而View中使用X:Name="ActivateItem"標(biāo)簽),其具體代碼為:
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());
}
}
}
此時(shí),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 . 對(duì)于View,只需把CalculatorViewModel對(duì)應(yīng)的CalculatorView作為ContentControl控件嵌入ShellView即可。此時(shí)ShellView的代碼調(diào)整為:
<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>
另外提一點(diǎn),向ViewModel A中嵌入ViewModel B,一般來說需要做的操作是:
在A的view中使用ContentControl,綁定B的ViewModel只需使用語(yǔ)句cal:View.Model="{Binding BViewModel}"即可,而B的view是UserControl就可以啦。
此時(shí)CalculatorView是一個(gè)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>
好啦,就醬,由于本例中邏輯并不復(fù)雜,Model暫時(shí)用不上,對(duì)于復(fù)雜一點(diǎn)的項(xiàng)目,Model主要負(fù)責(zé)數(shù)據(jù)的讀取,如文件操作、數(shù)據(jù)庫(kù)操作、service調(diào)用等,以后有機(jī)會(huì)舉例具體來說。
如果需要持久化(persistent),則還需給給每對(duì)M-VM(Model和ViewModel)加入State,這個(gè)實(shí)際工程中也用得特別多。
>>>6.功能舉例??<? <? <
Calculator主頁(yè):
點(diǎn)擊按鈕“ShowCalculator”即可看到具體的計(jì)算器~
乘法舉例:
除法舉例:
最后附上代碼:
CaliburnMicro-Calculator: A simple Calculator using Caliburn.Micro
https://github.com/yanglr/CaliburnMicro-Calculator,
歡迎fork和star,如有改進(jìn)意見歡迎提交pull request~
原文地址:
https://blog.csdn.net/lzuacm/article/details/80559517
更多精彩文章,歡迎訪問本人博客https://enjoy233.cnblogs.com 或 知乎搜索「Bravo Yeung」.
歡迎轉(zhuǎn)發(fā)到朋友圈,公眾號(hào)轉(zhuǎn)載請(qǐng)后臺(tái)聯(lián)系本人申請(qǐng)授權(quán)~
推薦閱讀
中英文電子書下載網(wǎng)站大搜羅
英語(yǔ)語(yǔ)法工具 | 那些可以糾正英語(yǔ)文章中語(yǔ)法的神器們
開發(fā)者見聞 | ASP.NET Core開發(fā)者路線圖
點(diǎn)擊在看的人,
2019都會(huì)變得特別好看
總結(jié)
以上是生活随笔為你收集整理的WPF框架教程 | 从0到1:使用Caliburn.Micro(WPF和MVVM)开发简单的计算器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Build 2019:微软正式宣布 .N
- 下一篇: 树莓派也跑Docker和.NET Cor