一、概述
本文与其说是MVVMLight框架的学习,不如说是温故一下数据的双向绑定。
二、Demo
建立好MVVMLight框架后的Wpf工程后,建立一个Model。Model、View以及ViewModel的代码如下:
1 using GalaSoft.MvvmLight; 2 3 namespace MvvmLightDemo1.Model 4 { 5 public class WelcomeModel : ObservableObject 6 { 7 private string welcomeMsg; 8 public string WelcomeMsg 9 { 10 get { return welcomeMsg; } 11 set { welcomeMsg = value; RaisePropertyChanged(() => WelcomeMsg); } 12 } 13 } 14 15 }
1 using GalaSoft.MvvmLight; 2 using MvvmLightDemo1.Model; 3 4 namespace MvvmLightDemo1.ViewModel 5 { 6 public class MainViewModel : ViewModelBase 7 { 8 private WelcomeModel welcomeModel; 9 public WelcomeModel WelcomeModel 10 { 11 get { return welcomeModel; } 12 set { welcomeModel = value; RaisePropertyChanged(() => WelcomeModel); } 13 } 14 /// <summary> 15 /// Initializes a new instance of the MainViewModel class. 16 /// </summary> 17 public MainViewModel() 18 { 19 WelcomeModel = new WelcomeModel() { WelcomeMsg = "Welcome to MVVMLight World!" }; 20 } 21 } 22 }
1 using CommonServiceLocator; 2 using GalaSoft.MvvmLight.Ioc; 3 4 namespace MvvmLightDemo1.ViewModel 5 { 6 /// <summary> 7 /// This class contains static references to all the view models in the 8 /// application and provides an entry point for the bindings. 9 /// </summary> 10 public class ViewModelLocator 11 { 12 /// <summary> 13 /// Initializes a new instance of the ViewModelLocator class. 14 /// </summary> 15 public ViewModelLocator() 16 { 17 ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); 18 SimpleIoc.Default.Register<MainViewModel>(); 19 } 20 21 public MainViewModel Main 22 { 23 get 24 { 25 return ServiceLocator.Current.GetInstance<MainViewModel>(); 26 } 27 } 28 29 public static void Cleanup() 30 { 31 // TODO Clear the ViewModels 32 } 33 } 34 }
1 <Window x:Class="MvvmLightDemo1.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:MvvmLightDemo1" 7 mc:Ignorable="d" 8 Title="MVVMLIghtDemo1" Height="350" Width="525" Background="#FF699DC1"> 9 <Window.DataContext> 10 <Binding Path="Main" Source="{StaticResource Locator}"></Binding> 11 </Window.DataContext> 12 <Grid> 13 <StackPanel > 14 <TextBlock Text="{Binding WelcomeModel.WelcomeMsg}" FontSize="28" Foreground="#FFBB4913" HorizontalAlignment="Center"/> 15 <StackPanel Orientation="Horizontal"> 16 <Label Content="修改信息:" VerticalContentAlignment="Center" FontSize="20" Foreground="#FFC55D21"></Label> 17 <TextBox Text="{Binding Path=WelcomeModel.WelcomeMsg,Mode=TwoWay}" FontSize="20" Foreground="#FFBB4913"/> 18 <Button Content="LostFocus" Background="#FF22A658"></Button> 19 </StackPanel> 20 21 </StackPanel> 22 <StackPanel VerticalAlignment="Top" HorizontalAlignment="Center" > 23 24 </StackPanel> 25 </Grid> 26 </Window>
在View中,我们分别让一个TextBox和一个TextBlock绑定WelcomeModel中的WelcomeMsg属性
当我们在TextBox中输入文本的时候,利用双向绑定更新WelcomeModel中的WelcomeMsg属性,WelcomeMsg属性又通过RaisePropertyChanged来激发属性变更的事件,通知UI,如此一来,界面上的TextBlock中的内容就会更新。
但是,当我们运行以上程序的时候,修改TextBox里的内容,TextBlock中的内容并没有实时更新,而是需要按键盘上的Tab键或者点击LostFocus按钮,让TextBox失去焦点。
这就引出了一个问题,当目标更新的时候,数据源是否更新以及更新的时机?
为了解决这个问题,我们可以使用Binding的UpdateSourceTrigger和Mode属性
UpdateSourceTrigger属性的作用:当做何种改变的时候通知数据源我们做了改变,默认值是LostFocus,这就解释了为什么我们上述程序需要TextBox失去焦点的时候,TextBlock的内容才会更新。
UpdateSourceTrigger可以取以下值:
枚举类型 | 说明 |
Default | 默认值(默认LostFocus) |
Explicit | 当应用程序调用 UpdateSource 方法时生效 |
LostFocus | 失去焦点的时候触发 |
PropertyChanged | 属性改变时立即触发 |
为了让TextBlock中的内容随着TextBox的内容实时变化,我们可以将绑定修改成如下格式:
<TextBox Text="{Binding Path=WelcomeModel.WelcomeMsg,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" FontSize="20" Foreground="#FFBB4913"/>
Mode属性取值如下:
通过以上Demo,我们应达成以下共识:
1)ViewModel => View更新的时候,我们一般在属性的set块中加入RaisePropertyChanged,它的作用是当数据源改变的时候,会触发PropertyChanged事件,通知UI属性发生了变更;
2)View => ViewModel 更新的时候,我们一般利用Binding的UpdateSourceTrigger和Mode属性。