Behavior的使用详解

2016-02-14 10:31:42来源:作者:Aran人点击

微软的Behavior一直都是Windows Store/WPF/Silverlight开发者青睐的一个功能,在理想的状况下,开发者只需要提供Behavior库,设计人员就可以通过XAML中选择相应的Behavior来实现需要的功能,从而大大降低了UI与逻辑代码的耦合度。 什么是Behavior呢?其实就是用于附加在某个控件上的行为操作,它有三个要素:何时触发、触发对象、要实现的功能。 根据触发的时机 Blend for Visual Studio 2013提供了三种不同的Behavior:

EventTriggerBehavior:使用事件(event)来触发行为 DataTriggerBehavior:使用数据变化来触发行为 IncrementalUpdateBehavior:当GridView、ListView控件增量更新时触发行为

本片文章不对IncrementalUpdateBehavior做介绍,IncrementalUpdateBehavior功能太复杂,以后讨论。

Action指某个特性的功能,需要配合Behavior一起来使用,Blend 2013为我们提供了七种不同的Action:

CallMethodAction:调用某个特定的方法 ChangePropertyAction:改变某个属性的值 ControlStoryboardAction:控制动画板状态 GoToStateAction:改变控件状态 InvokeCommandAction:调用某个Command NavigeteToPageAction:导航到某个页面 PlaySoundAction:播放声音

基本上我们依靠上面的这些Action配合Behavior就可以完成大部分的功能下面来看看每个Behavior具体怎么使用的。 EventTriggerBehavior是系统默认的Behavior,每一个Action动作被拖拽到控件上时,系统都会默认给加上一个EventTriggerBehavior,EventTriggerBehavior还有三个用于设置触发方式的属性:

Binding:设定需要比较的属性 ComparationCondition:设定比较的条件 Value:设置比较的值

但是无论使用哪种Behavior,都是需要Action配合的,接下来我们看看七种Action的使用案例:

1. NavigateToPageAction

这个Action最简单,是为了实现页面跳转的,通过它我们能轻松导航到其他Page上,这里准备了两个Page:MainPage.xaml、Page1.xaml,MainPage中有一个Button,我们在Blend的资源选项卡中拖出一个NavigateToPageAction到这个Button上,修改Common中的TargetPage属性为要跳转的页面Page1:

代码会生产:

<Button Content="跳转"><Interactivity:Interaction.Behaviors><Core:EventTriggerBehavior EventName="Click"><Core:NavigateToPageAction TargetPage="Behavior_Sample.Page1"/></Core:EventTriggerBehavior></Interactivity:Interaction.Behaviors></Button> 2. CallMethodAction

CallMethodAction是用来调用逻辑方法的,它和事件驱动机制效果类似,但是和事件驱动机制有一个很大的不同点就是CallMethodAction是可以调用到ViewModel中的方法来实现UI与逻辑代码的分离,杜绝出现code behind那样的事件驱动方法,程序员欸UI设计师提供一个方法调用入口,而不用知道方法具体的实现细节。

我们先通过“NuGet程序包管理器控制台”中使用命令:Install-Package Mvvmlight来为项目添加MVVM Light组件框架下的ViewModel中增加一个方法

public async void HelloWorld() { var dialog = new MessageDialog("Hello Behavior") {DefaultCommandIndex = 1}; await dialog.ShowAsync(); }

然后我们在UI中点击按钮时使用CallMethodAction 调用这个方法,TargetObject设置为ViewModel实例,MethodName设置为要调用的方法:

代码会生成:

3. ChangePropertyAction

ChangePropertyAction使用也很简单,使用这个Action可以操作页面元素的一些属性,如果有多个事件,则可以添加多个ChangePropertyAction到该元素下,这里我们来实现点击按钮后改变该按钮的背景色,我们在Blend中拖入一个ChangPropertyAction行为到Button控件上,然后设置PropertyName为元素的某个属性,这里设置为Background属性,值设置为红色,TargetObject属性设置为某个元素,我们这里设置为自身,意为改变当click button时改变自身的Background为红色:

生成代码:

<Button x:Name="button" Content="Click Me"><Interactivity:Interaction.Behaviors><Core:EventTriggerBehavior EventName="Click"><Core:ChangePropertyAction TargetObject="{Binding ElementName=button}" PropertyName="Background"><Core:ChangePropertyAction.Value><SolidColorBrush Color="Red"/></Core:ChangePropertyAction.Value></Core:ChangePropertyAction></Core:EventTriggerBehavior></Interactivity:Interaction.Behaviors></Button> 4. ControlStoryboardAction

ControlStoryboardAction行为是操作故事版动画的,可以对故事版进行Stop和Begin操作,有了它我们便可以不用code behind的方式便可自由控制动画面板 我们现在添加一个简单的动画,使一个小球在View中运动,再添加三个按钮来控制小球动画状态:

<Page.Resources><Storyboard x:Name="EllipseStoryboard" RepeatBehavior="Forever"><DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="ellipse"><EasingDoubleKeyFrame KeyTime="0" Value="-573.134"><EasingDoubleKeyFrame.EasingFunction><CircleEase EasingMode="EaseOut"/></EasingDoubleKeyFrame.EasingFunction></EasingDoubleKeyFrame><EasingDoubleKeyFrame KeyTime="0:0:1" Value="577.612"><EasingDoubleKeyFrame.EasingFunction><CircleEase EasingMode="EaseOut"/></EasingDoubleKeyFrame.EasingFunction></EasingDoubleKeyFrame><EasingDoubleKeyFrame KeyTime="0:0:2" Value="-582.089"><EasingDoubleKeyFrame.EasingFunction><CircleEase EasingMode="EaseOut"/></EasingDoubleKeyFrame.EasingFunction></EasingDoubleKeyFrame><EasingDoubleKeyFrame KeyTime="0:0:3" Value="575.911"><EasingDoubleKeyFrame.EasingFunction><CircleEase EasingMode="EaseOut"/></EasingDoubleKeyFrame.EasingFunction></EasingDoubleKeyFrame></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="ellipse"><EasingDoubleKeyFrame KeyTime="0" Value="-283.582"><EasingDoubleKeyFrame.EasingFunction><CircleEase EasingMode="EaseOut"/></EasingDoubleKeyFrame.EasingFunction></EasingDoubleKeyFrame><EasingDoubleKeyFrame KeyTime="0:0:1" Value="-280.597"><EasingDoubleKeyFrame.EasingFunction><CircleEase EasingMode="EaseOut"/></EasingDoubleKeyFrame.EasingFunction></EasingDoubleKeyFrame><EasingDoubleKeyFrame KeyTime="0:0:2" Value="241.791"><EasingDoubleKeyFrame.EasingFunction><CircleEase EasingMode="EaseOut"/></EasingDoubleKeyFrame.EasingFunction></EasingDoubleKeyFrame><EasingDoubleKeyFrame KeyTime="0:0:3" Value="247.791"><EasingDoubleKeyFrame.EasingFunction><CircleEase EasingMode="EaseOut"/></EasingDoubleKeyFrame.EasingFunction></EasingDoubleKeyFrame></DoubleAnimationUsingKeyFrames></Storyboard></Page.Resources> <Grid HorizontalAlignment="Center" > <StackPanel VerticalAlignment="Center"><Ellipse x:Name="ellipse" Width="50" Height="50" Fill="Red" RenderTransformOrigin="0.5,0.5"> <Ellipse.RenderTransform> <CompositeTransform/> </Ellipse.RenderTransform></Ellipse><Button x:Name="StartBtn" Content="开始"></Button><Button x:Name="PuaseBtn" Content="暂停"></Button><Button x:Name="StopBtn" Content="停止"></Button> </StackPanel></Grid>

在Blend中为每个按钮拖入一个ControlStoryboardAction行为控件,每个行为的ControlStoryboardOption设置为动画对应的状态,Storyboard设置为要控制哪个动画版,如下:

生成的代码:

<Button x:Name="StartBtn" Content="开始"><Interactivity:Interaction.Behaviors><Core:EventTriggerBehavior EventName="Click"><Media:ControlStoryboardAction Storyboard="{StaticResource EllipseStoryboard}"/></Core:EventTriggerBehavior></Interactivity:Interaction.Behaviors></Button><Button x:Name="PuaseBtn" Content="暂停"><Interactivity:Interaction.Behaviors><Core:EventTriggerBehavior EventName="Click"><Media:ControlStoryboardAction ControlStoryboardOption="Pause" Storyboard="{StaticResource EllipseStoryboard}"/></Core:EventTriggerBehavior></Interactivity:Interaction.Behaviors></Button><Button x:Name="StopBtn" Content="停止"><Interactivity:Interaction.Behaviors><Core:EventTriggerBehavior EventName="Click"><Media:ControlStoryboardAction ControlStoryboardOption="Stop" Storyboard="{StaticResource EllipseStoryboard}"/></Core:EventTriggerBehavior></Interactivity:Interaction.Behaviors></Button> 5. GoToStateAction

这个行为控件是用来转换控件的视图状态的,可以从某个状态转变为另一个VisualState状态。

我们可以为某些元素提供一组VisualState,为每个VisualState设计一组动画,然后通过GoToStateAction来为UI上的操作提供动画效果。

下面我们还是用上面的小球做例子,我们给小球添加两个状态组,一个是循环作放大操作的状态组:OnMouse,另一个是缩放一下的状态组:DropMouse,然后我们在Blend中为小球添加两个GoToStateAction行为控件:

前台代码:

<Grid HorizontalAlignment="Center"><VisualStateManager.VisualStateGroups><VisualStateGroup x:Name="VisualStateGroup"><VisualStateGroup.Transitions><VisualTransition GeneratedDuration="0" To="OnMouse"><Storyboard RepeatBehavior="Forever"><DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)" Storyboard.TargetName="ellipse"><EasingDoubleKeyFrame KeyTime="0" Value="1"><EasingDoubleKeyFrame.EasingFunction><CircleEase EasingMode="EaseOut"/></EasingDoubleKeyFrame.EasingFunction></EasingDoubleKeyFrame><EasingDoubleKeyFrame KeyTime="0:0:1" Value="8.92"><EasingDoubleKeyFrame.EasingFunction><CircleEase EasingMode="EaseOut"/></EasingDoubleKeyFrame.EasingFunction></EasingDoubleKeyFrame></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)" Storyboard.TargetName="ellipse"><EasingDoubleKeyFrame KeyTime="0" Value="1"><EasingDoubleKeyFrame.EasingFunction><CircleEase EasingMode="EaseOut"/></EasingDoubleKeyFrame.EasingFunction></EasingDoubleKeyFrame><EasingDoubleKeyFrame KeyTime="0:0:1" Value="8.92"><EasingDoubleKeyFrame.EasingFunction><CircleEase EasingMode="EaseOut"/></EasingDoubleKeyFrame.EasingFunction></EasingDoubleKeyFrame></DoubleAnimationUsingKeyFrames></Storyboard></VisualTransition><VisualTransition From="OnMouse" GeneratedDuration="0"><Storyboard><DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)" Storyboard.TargetName="ellipse"><EasingDoubleKeyFrame KeyTime="0" Value="8.9"/><EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="1"/></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)" Storyboard.TargetName="ellipse"><EasingDoubleKeyFrame KeyTime="0" Value="8.9"/><EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="1"/></DoubleAnimationUsingKeyFrames></Storyboard></VisualTransition><VisualTransition GeneratedDuration="0" To="DropMouse"><Storyboard><DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)" Storyboard.TargetName="ellipse"><EasingDoubleKeyFrame KeyTime="0" Value="1"/><EasingDoubleKeyFrame KeyTime="0:0:1" Value="0.5"/></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)" Storyboard.TargetName="ellipse"><EasingDoubleKeyFrame KeyTime="0" Value="1"/><EasingDoubleKeyFrame KeyTime="0:0:1" Value="0.5"/></DoubleAnimationUsingKeyFrames></Storyboard></VisualTransition><VisualTransition From="DropMouse" GeneratedDuration="0"><Storyboard><DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)" Storyboard.TargetName="ellipse"><EasingDoubleKeyFrame KeyTime="0" Value="0.5"/><EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="1"/></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)" Storyboard.TargetName="ellipse"><EasingDoubleKeyFrame KeyTime="0" Value="0.5"/><EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="1"/></DoubleAnimationUsingKeyFrames></Storyboard></VisualTransition></VisualStateGroup.Transitions><VisualState x:Name="OnMouse"/><VisualState x:Name="DropMouse"/></VisualStateGroup></VisualStateManager.VisualStateGroups><StackPanel VerticalAlignment="Center"><Ellipse x:Name="ellipse" Width="50" Height="50" Fill="Red" RenderTransformOrigin="0.5,0.5"><Interactivity:Interaction.Behaviors><Core:EventTriggerBehavior EventName="PointerEntered"><Core:GoToStateAction StateName="OnMouse"/></Core:EventTriggerBehavior> <Core:EventTriggerBehavior EventName="PointerExited"><Core:GoToStateAction StateName="DropMouse"/></Core:EventTriggerBehavior></Interactivity:Interaction.Behaviors><Ellipse.RenderTransform><CompositeTransform/></Ellipse.RenderTransform></Ellipse> </StackPanel></Grid>

Blend中我们为两个EventTriggerBehavior的EventName分别指定PointerEntered事件和PointerExited事件,每个EventTriggerBehavior中的GoToStateAction中的StateName分别设置为两个状态:

6. InvokeCommandAction

InvokeCommandAction的作用和直接使用Command是一样的,但是Command只支持三种控件:基于Button的,基于Menu的以及Hyperlink的Click事件。

而InvokeCommandAction则是能在任何EventTriggerBehavior与DataTriggerBehavior能够触发的地方调用。

这里做个例子,我们在输入文本框的时候进行文本字数统计,并且有个开关控件来控制是否在输入的时候进行统计,我们在页面上放入一个TextBox和一个ToggleSwitch开关控件,然后在ViewModel中创建一个名为TextChangedCommand的RelayCommand类型属性,TextChangedCommand是用来绑定文本框KeyUp事件的。再创建一个int类型的TxtLength属性用来绑定文本字数,还有一个bool类型的Switch属性用来绑定是否进行统计控件。

ViewModel代码如下:

using GalaSoft.MvvmLight;using GalaSoft.MvvmLight.Command;namespace Behavior_Sample.ViewModel{public class MainViewModel : ViewModelBase{/// <summary>/// Initializes a new instance of the MainViewModel class./// </summary>public MainViewModel(){TextChangedCommand = new RelayCommand<string>((text) =>{TxtLength = text.Length;// ReSharper disable once ExplicitCallerInfoArgumentRaisePropertyChanged("TxtLength");}, (text) => Switch);}public RelayCommand<string> TextChangedCommand { get; set; }public int TxtLength { get; set; }public bool Switch { get; set; }}}

然后我们在Blend中给TextBox拖入一个InvokeCommandAction行为如下:

前台代码如下:

<Pagexmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="using:Behavior_Sample"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:Interactivity="using:Microsoft.Xaml.Interactivity" xmlns:Core="using:Microsoft.Xaml.Interactions.Core"xmlns:Media="using:Microsoft.Xaml.Interactions.Media"x:Class="Behavior_Sample.MainPage"mc:Ignorable="d" Background="Black"><Page.DataContext><Binding Path="Main" Source="{StaticResource Locator}"/></Page.DataContext><Grid HorizontalAlignment="Center"><StackPanel VerticalAlignment="Center"><StackPanel Orientation="Horizontal"><TextBox x:Name="textBox" Width="200"><Interactivity:Interaction.Behaviors><Core:EventTriggerBehavior EventName="KeyUp"><Core:InvokeCommandAction Command="{Binding TextChangedCommand}" CommandParameter="{Binding Text, ElementName=textBox}"/></Core:EventTriggerBehavior></Interactivity:Interaction.Behaviors></TextBox><TextBlock Text="{Binding TxtLength}" VerticalAlignment="Center"/></StackPanel><StackPanel Orientation="Horizontal"><ToggleSwitch OffContent="字数统计关" OnContent="字数统计开" IsOn="{Binding Switch,Mode=TwoWay}" /></StackPanel></StackPanel></Grid></Page> 7. PlaySoundAction

PlaySoundAction控件是用来播放音频文件的,这个就不多做介绍了!生成代码如下:

<Grid HorizontalAlignment="Center"><StackPanel VerticalAlignment="Center"><Button Content="播放音乐"><Interactivity:Interaction.Behaviors><Core:EventTriggerBehavior EventName="Click"><Media:PlaySoundAction Source="老男孩.mp3"/></Core:EventTriggerBehavior></Interactivity:Interaction.Behaviors></Button></StackPanel></Grid>

上面这些Behavior的使用基本已经满足了日常开发需求,不仅如此,你也可以自定义你自己的Behavior和Action!

参考资料: https://msdn.microsoft.com/zh-cn/library/system.windows.interactivity(v=expression.40).aspx

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台