Windows Phone 7 MVVM模式通讯方式之实现Command
MVVM模式的View与ViewModel的三大通讯方式:Binding Data(实现数据的传递)、Command(实现操作的调用)和Attached Behavior(实现控件加载过程中的操作)。
下面通过一个实例实现MVVM模式的Command通讯
(1)MainPage.xaml文件的代码,实现View层
<phone:PhoneApplicationPage x:Class="CommandDemo.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:my="clr-namespace:CommandDemo.ViewModel" xmlns:my_Interactivity="clr-namespace:CommandDemo.Command" xmlns:Custom="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:ic="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions" mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" shell:SystemTray.IsVisible="True"> <!--设置整个页面的上下文数据DataContext为RadiusViewModel--> <phone:PhoneApplicationPage.DataContext> <my:RadiusViewModel/> </phone:PhoneApplicationPage.DataContext> <Grid x:Name="LayoutRoot" Background="Transparent"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> <TextBlock x:Name="ApplicationTitle" Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/> <TextBlock x:Name="PageTitle" Text="Command" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> </StackPanel> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <Ellipse Fill="Red" Height="{Binding Radius}" Width="{Binding Radius}" HorizontalAlignment="Left" Margin="119,84,0,0" Name="ellipse1" Stroke="Black" StrokeThickness="1" VerticalAlignment="Top" /> <Button Content="小" Height="72" HorizontalAlignment="Left" Margin="0,385,0,0" Name="button1" VerticalAlignment="Top" Width="160"> <Custom:Interaction.Triggers> <Custom:EventTrigger EventName="Click"> <my_Interactivity:ExecuteCommandAction CommandName="MinRadius"/> </Custom:EventTrigger> </Custom:Interaction.Triggers> </Button> <Button Content="中" Height="72" HorizontalAlignment="Left" Margin="149,384,0,0" Name="button2" VerticalAlignment="Top" Width="160" > <Custom:Interaction.Triggers> <Custom:EventTrigger EventName="Click"> <my_Interactivity:ExecuteCommandAction CommandName="MedRadius"/> </Custom:EventTrigger> </Custom:Interaction.Triggers> </Button> <Button Content="大" Height="72" HorizontalAlignment="Left" Margin="299,382,0,0" Name="button3" VerticalAlignment="Top" Width="160" > <Custom:Interaction.Triggers> <Custom:EventTrigger EventName="Click"> <my_Interactivity:ExecuteCommandAction CommandName="MaxRadius"/> </Custom:EventTrigger> </Custom:Interaction.Triggers> </Button> </Grid> </Grid> </phone:PhoneApplicationPage>
(2)RadiusViewModel.cs文件的代码,实现ViewModel层
using System; using System.Windows.Input; using System.ComponentModel; using Microsoft.Expression.Interactivity.Core; namespace CommandDemo.ViewModel { public class RadiusViewModel : INotifyPropertyChanged { private Double radius; public RadiusViewModel() { Radius = 0; MinRadius = new ActionCommand(p => Radius = 100); MedRadius = new ActionCommand(p => Radius = 200); MaxRadius = new ActionCommand(p => Radius = 300); } public event PropertyChangedEventHandler PropertyChanged; public ICommand MinRadius { get; private set; } public ICommand MedRadius { get; private set; } public ICommand MaxRadius { get; private set; } public Double Radius { get { return radius; } set { radius = value; OnPropertyChanged("Radius"); } } protected virtual void OnPropertyChanged(string propertyName) { var propertyChanged = PropertyChanged; if(propertyChanged != null) propertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } }
(3)ExecuteCommandAction.cs类,实现Command操作
using System; using System.Windows; using System.Windows.Input; using System.Windows.Interactivity; using System.Reflection; namespace CommandDemo.Command { public class ExecuteCommandAction : TriggerAction<FrameworkElement> { public static readonly DependencyProperty CommandNameProperty = DependencyProperty.Register("CommandName", typeof(string), typeof(ExecuteCommandAction), null); public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(ExecuteCommandAction), null); protected override void Invoke(object parameter) { if (AssociatedObject == null) return; ICommand command = null; var dataContext = AssociatedObject.DataContext; foreach (var info in dataContext.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) { if (IsCommandProperty(info) && String.Equals(info.Name, CommandName, StringComparison.Ordinal)) { command = (ICommand)info.GetValue(dataContext, null); break; } } if ((command != null) && command.CanExecute(CommandParameter)) { command.Execute(CommandParameter); } } private static bool IsCommandProperty(PropertyInfo property) { return typeof(ICommand).IsAssignableFrom(property.PropertyType); } public string CommandName { get { return (string)GetValue(CommandNameProperty); } set { SetValue(CommandNameProperty, value); } } public object CommandParameter { get { return GetValue(CommandParameterProperty); } set { SetValue(CommandParameterProperty, value); } } } }