Caliburn.Micro(MVVM框架)
一、首启窗体设置
1. 创建一个新的WPF应用程序并添加NuGet包:Caliburn.Micro
2. 删除项目自带的主窗口文件MainWindow.xaml
3. 在App.xaml项目文件中,删除StartupUri="MainWindow.xaml"节点特性,并添加ResourceDictionary:
<Application x:Class="Machine.UI.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Machine.UI"> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary> <local:Bootstrapper x:Key="Bootstrapper"/> </ResourceDictionary> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> </Application>
4. 新建Bootstrapper.cs类,继承:BootstrapperBase,并在此类中设置首启窗体(这里设置ShellView为首启窗体):
1 public class Bootstrapper:BootstrapperBase 2 { 3 public Bootstrapper() 4 { 5 Initialize(); 6 } 7 8 protected override void OnStartup(object sender, StartupEventArgs e) 9 { 10 DisplayRootViewFor<ShellViewModel>(); 11 } 12 }
二、命名规范
1.View和ViewModel的关联
在项目中新建文件夹Models、Views、ViewModels(一定要记得加s),前缀名相同的View和ViewModel默认是一组(例如:ShellView和ShellViewModel),会自动关联。
2. 属性关联
ViewModel中:
写具有通知功能的属性,可以写成自定义的代码模板(例如:我写成了propcn或propcnh),
可以只通知自己的同名UI属性(FirstName),也可通知相关联的其他UI属性(FullName),也可通知相关联的按钮使能方法(CanClearText),
赋初值是给字段赋值
1 private string _firstName = "Tim"; 2 public string FirstName 3 { 4 get 5 { 6 return _firstName; 7 } 8 set 9 { 10 _firstName = value; 11 NotifyOfPropertyChange(() => FirstName); 12 NotifyOfPropertyChange(() => FullName);
13 NotifyOfPropertyChange(() => CanClearText); 14 } 15 } 16 17 public string FullName 18 { 19 get { return $"{FirstName} {LastName}"; } 20 }
View中:
一对一时:可直接关联给标签的名字<TextBox x:Name="CityName"/>
一对多时:使用绑定<TextBox Text="{Binding Path=CityName,Mode=OneWay}"/>
关联的是属性的属性时使用下划线:< ... x:Name="SelectedPerson_FirstName"/>
3. 方法关联
View中按钮关联点击方法:
<Button Grid.Row="4" Grid.Column="1" cal:Message.Attach="[Event Click] = [Action ClearText]">Clear Names</Button>
可以在方法中传入参数,参数是一个集合:
<Button cm:Message.Attach="[Event Click] = [Action Show(‘woo~’)]">
可以用分号;来表示多个方法,如:
<Button cm:Message.Attach="[Event MouseEnter] = [Action Show('Enter')]; [Event MouseLeave] = [Action Show('Leave')]" />
小括号()传入参数时不仅可以传入字符串,也可以使用绑定,如:
<TextBlock x:Name="txtBlock" Text="woo~"/> <Button cm:Message.Attach="[Event Click] = [Action Show(txtBlock.Text)]">
可以与其他控件绑定,点击按钮执行该控件的某方法:
<ListBox x:Name="lstBox" SelectionMode="Extended"> <ListBoxItem>123</ListBoxItem> <ListBoxItem>123</ListBoxItem> <ListBoxItem>123</ListBoxItem> </ListBox> <Button cm:Action.Target="{Binding ElementName=lstBox}" Focusable="False" cm:Message.Attach="[Event Click] = [Action SelectAll]">
有多种按钮事件时,View中添加xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity",并将关联方法们这样写:
1 <Button Grid.Row="4" Grid.Column="1" Content="Clear Names"> 2 <i:Interaction.Triggers> 3 <i:EventTrigger EventName="Click"> 4 <cal:ActionMessage MethodName="ClearText" /> 5 </i:EventTrigger> 6 </i:Interaction.Triggers> 7 </Button>
ViewModel中按钮的点击方法和使能方法:
注意:使能方法只受与UI关联的属性影响,其他的可绑定按钮本身的IsEnable属性操作。
1 public bool CanClearText() 2 { 3 if (String.IsNullOrWhiteSpace(FirstName) && String.IsNullOrWhiteSpace(LastName)) 4 { 5 return false; 6 } 7 else 8 { 9 return true; 10 } 11 } 12 13 public void ClearText() 14 { 15 FirstName = ""; 16 LastName = ""; 17 }
三、主子窗体
1. 主窗体
Windows类型,通常让ViewModel继承 Conductor<object>,下面介绍三种继承的区别:
Conductor<T> ——管理一个单一Screen。一旦激活一个新的屏幕,任何先前的Screen会被关闭,会通过 conductor 进行管理。用于非常简单的导航/显示(navigation/display)方案。
Conductor<T>.Collection.OneActive ——管理多个Screen,并允许在同一时间里存在一个激活的Screen,很像一个选项卡控件。当Screen被激活,以前的活动Screen被停用,不会关闭,也不会通过conductor管理遗留。Screens可以显式地关闭和移除。这种类型的conductor还负责激活Screens中的某一个,如果当前活动Screen关闭。
Conductor<T>.Collection.AllActive ——和上一个Conductor非常类似,但允许多个屏幕处于活动状态。
2. 子窗体
User Control类型,ViewModel继承 Screen
3. 主窗体中调用子窗体
View中:<ContentControl x:Name="ActiveItem"/>
ViewModel中:ActivateItem(new GlobalViewModel());
Action的参考:解析Caliburn.Micro(二)