WPF使用MVVMLight的ViewModel 访问控件的属性方法事件以及多页面传递信息
运行效果图
程序集整体如下
<Window x:Class="MVVMLightDemo.View.MainView" 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:MVVMLightDemo.View" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" mc:Ignorable="d" Title="MainView" Height="450" Width="800"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="100"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <StackPanel Grid.Column ="0"> <Button Content="UI1" Command="{Binding UI1Command}" /> <Button Content="UI2" Command="{Binding UI2Command}"/> </StackPanel> <GridSplitter Grid.Row="0" Grid.Column="1" Width="5" HorizontalAlignment="Left" VerticalAlignment="Stretch" Background="#FFC1BDC5" Grid.RowSpan="2" /> <Grid Grid.Column="1"> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="100"/> </Grid.RowDefinitions> <GridSplitter Height="5" Grid.Row="0" Grid.Column="1" Background="#FFC1BDC5" HorizontalAlignment="Stretch" VerticalAlignment="Bottom"/> <Border Grid.Row ="0" BorderBrush="Gray" BorderThickness="1" > <ContentPresenter Content="{Binding Content}" Margin="5,0"/> <!--使用内容呈现器来切换界面--> </Border> <Border Grid.Row ="1" BorderBrush="Gray" BorderThickness="1"> <TextBox x:Name="LogTextBox" Text="{Binding TextLog}" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" > <i:Interaction.Triggers> <i:EventTrigger EventName="Loaded"> <i:InvokeCommandAction Command="{Binding Path=TextBoxLoadedCommand}" CommandParameter="{Binding ElementName=LogTextBox}"> </i:InvokeCommandAction> </i:EventTrigger> </i:Interaction.Triggers> </TextBox> </Border> </Grid> </Grid> </Window>
<UserControl x:Class="MVVMLightDemo.View.UI1View" 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:MVVMLightDemo.View" mc:Ignorable="d" d:DesignHeight="100" d:DesignWidth="200"> <Grid> <Button Content="UI1向日志界面传递信息" Command="{Binding BtnCommand}" HorizontalAlignment="Center" VerticalAlignment="Center"/> </Grid> </UserControl>
UI1界面里只有一个Button并绑定一个命令,单击这个按键会向日志里打印文本,UI2和UI1类似
<UserControl x:Class="MVVMLightDemo.View.UI2View" 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:MVVMLightDemo.View" mc:Ignorable="d" d:DesignHeight="100" d:DesignWidth="200"> <Grid> <Button Content="UI2向日志界面传递信息" Command="{Binding BtnCommand}" HorizontalAlignment="Left" VerticalAlignment="Top"/> </Grid> </UserControl>
三个UI界面对应的三个ViewModel分别如下
using GalaSoft.MvvmLight; using GalaSoft.MvvmLight.Command; using GalaSoft.MvvmLight.Messaging; using MVVMLightDemo.View; using System; using System.Windows.Controls; namespace MVVMLightDemo.ViewModel { /// <summary> /// This class contains properties that the main View can data bind to. /// <para> /// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel. /// </para> /// <para> /// You can also use Blend to data bind with the tool's support. /// </para> /// <para> /// See http://www.galasoft.ch/mvvm /// </para> /// </summary> public class MainViewModel : ViewModelBase { /// <summary> /// Initializes a new instance of the MainViewModel class. /// </summary> /// #region 成员 TextBox TextBoxLog = new TextBox(); public UserControl UserUI1 = new UI1View(); public UserControl UserUI2 = new UI2View(); #endregion #region 构造方法 public MainViewModel() { ///Messenger:信使 ///Recipient:收件人 Messenger.Default.Register<string>(this, "Log", msg => //注册Log消息 其内容是向日志文本追加文本 { TextLog += msg; }); } #endregion #region 绑定属性 //主页面的内容呈现器 private UserControl _content; public UserControl Content { get { return _content; } set { _content = value;RaisePropertyChanged(() => Content);} } //文本日志 private string textlog; public string TextLog { get { return textlog; } set { textlog = value; RaisePropertyChanged(() => TextLog); } } #endregion #region Button UI1命令 private RelayCommand ui1Command; public RelayCommand UI1Command { get { if (ui1Command == null) ui1Command = new RelayCommand(() => ExcuteUI1Command()); return ui1Command; } set { ui1Command = value; } } private void ExcuteUI1Command() { Content = UserUI1; } #endregion #region Button UI2命令 private RelayCommand ui2Command; public RelayCommand UI2Command { get { if (ui2Command == null) ui2Command = new RelayCommand(() => ExcuteUI2Command()); return ui2Command; } set { ui2Command = value; } } private void ExcuteUI2Command() { Content = UserUI2; } #endregion #region TextBox private RelayCommand<TextBox> textBoxLoadedCommand; public RelayCommand<TextBox> TextBoxLoadedCommand { get { if (textBoxLoadedCommand == null) textBoxLoadedCommand = new RelayCommand<TextBox>((p) => ExecuteTextBoxLoadedCommandCommand(p)); return textBoxLoadedCommand; } set { textBoxLoadedCommand = value; } } private void ExecuteTextBoxLoadedCommandCommand(TextBox p) { TextBoxLog = (System.Windows.Controls.TextBox)p;//TextBox加载的时候把自身最为参数传递到ViewModel里来,有了这个参数就可以在ViewModel中使用该控件的属性方法以及事件 TextBoxLog.IsReadOnly = true;//设为只读(使用控件的属性) TextBoxLog.TextChanged += TextBoxLog_TextChanged;//添加文本发生改变的事件(使用控件的事件) } private void TextBoxLog_TextChanged(object sender, TextChangedEventArgs e) { TextBoxLog.ScrollToEnd();//文本发生改变的时候让文本自动滚到底部(使用控件的方法) } #endregion } }
<TextBox x:Name="LogTextBox" Text="{Binding TextLog}" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" > <i:Interaction.Triggers> <i:EventTrigger EventName="Loaded"> <i:InvokeCommandAction Command="{Binding Path=TextBoxLoadedCommand}" CommandParameter="{Binding ElementName=LogTextBox}"> </i:InvokeCommandAction> </i:EventTrigger> </i:Interaction.Triggers> </TextBox>
在MainView.xaml中TextBox绑定了加载事件Loaded,这里绑定的事件命令的同时还传递了一个TextBox自身参数LogTextBox,这个参数会带到MainViewModel.cs文件中去
private RelayCommand<TextBox> textBoxLoadedCommand; public RelayCommand<TextBox> TextBoxLoadedCommand { get { if (textBoxLoadedCommand == null) textBoxLoadedCommand = new RelayCommand<TextBox>((p) => ExecuteTextBoxLoadedCommandCommand(p)); return textBoxLoadedCommand; } set { textBoxLoadedCommand = value; } } private void ExecuteTextBoxLoadedCommandCommand(TextBox p) { TextBoxLog = (System.Windows.Controls.TextBox)p;//TextBox加载的时候把自身最为参数传递到ViewModel里来,有了这个参数就可以在ViewModel中使用该控件的属性方法以及事件 TextBoxLog.IsReadOnly = true;//设为只读(使用控件的属性) TextBoxLog.TextChanged += TextBoxLog_TextChanged;//添加文本发生改变的事件(使用控件的事件) } private void TextBoxLog_TextChanged(object sender, TextChangedEventArgs e) { TextBoxLog.ScrollToEnd();//文本发生改变的时候让文本自动滚到底部(使用控件的方法) }
在MainViewModel.cs中操作该参数就像在后台文件中操作MainView.xaml.cs中操作LogTextBox是一样的,有了这个参数就可以在MainViewModel.cs中任意位置使用该控件的属性和方法了,如果想使用控件的事件直接在加载命令中注册即可。
在MainViewModel.cs构造方法中注册了一个信使名字叫做Log
public MainViewModel() { ///Messenger:信使 ///Recipient:收件人 Messenger.Default.Register<string>(this, "Log", msg => //注册Log消息 其内容是向日志文本追加文本 { TextLog += msg; }); }
注册了这个信使后,就可以在其他页面的ViewModel中直接发送消息,发送的消息除了是string类型还可以是自定义类类型
using GalaSoft.MvvmLight; using GalaSoft.MvvmLight.Command; using GalaSoft.MvvmLight.Messaging; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MVVMLightDemo.ViewModel { public class UI1ViewModel : ViewModelBase { private RelayCommand btnCommand; public RelayCommand BtnCommand { get { if (btnCommand == null) btnCommand = new RelayCommand(() => ExcuteBtnCommand()); return btnCommand; } set { btnCommand = value; } } private void ExcuteBtnCommand() { Messenger.Default.Send<string>("我是UI1!\n", "Log");//向Log发送消息 (追加文本) } } }
using GalaSoft.MvvmLight; using GalaSoft.MvvmLight.Command; using GalaSoft.MvvmLight.Messaging; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MVVMLightDemo.ViewModel { public class UI2ViewModel : ViewModelBase { private RelayCommand btnCommand; public RelayCommand BtnCommand { get { if (btnCommand == null) btnCommand = new RelayCommand(() => ExcuteBtnCommand()); return btnCommand; } set { btnCommand = value; } } private void ExcuteBtnCommand() { Messenger.Default.Send<string>("我是UI2!\n", "Log");//向Log发送消息 (追加文本) } } }