zoukankan      html  css  js  c++  java
  • Silverlight之Action和Behavior

    首先看下创建Action和Behavior的首要条件,由于Action和Behavior原本是Blend特有的,不过没关系,可以在Blend的目录中找到我们需要的dll文件

    打开

    c:\Program Files\MicrosoftSDKs\Expression\Blend\Silverlight\v4.0\Librariest目录找到System.Windows.Interactivity.dll,这个就是需要的核心文件

    Behavior包含三个元素,trigger,action,behavior

    这三个东西是需要合作完成任务的,当触发一些事件或者调用一个Action则触发一个Trigger;Trigger和Action组成一个简单的Behavior。(Trigger是用来监听,Action用来响应)


    创建Action,通常来说我们会创建一个新的Silverlight 类库来存放这些东西.创建好Silverlight类库之后开始创建真正的Action类

    public class PlaySoundAction : TriggerAction<FrameworkElement>

    所有的Action都继承自TriggerAction类,因为一个Action是通过Trigger来触发的。通常的话这个TriggerAction的泛型为FrameworkElement或者UIElement.

    当一个Trigger被触发了,就会调用Action的Invoke方法,所以,我们需要重写Invoke方法来实现自定义的功能。

    下面来一个完整的例子,例子的要求是,当点击一个按钮播放一个音频声音,当然这个还是使用MiediaElement来播放,只是说通过Action的方式来实现。

    首先创建一个Action类,名字为PlaySoundAction:

    public class PlaySoundAction : TriggerAction<FrameworkElement>

    每一个Action都应该有自己的属性(依赖属性)的,这样才能通用的来达到通用的效果,在这个例子中定义一个Source属性,表示音频的地址,

    依赖属性的类型就是

    DependencyProperty ,通过DependencyProperty.Register创建一个依赖属性,参数一就是 暴漏给调用者的属性名字,即代码中的Source属性,参数二为当前依赖属性的类型,
    由于是表示音频的地址,所以应该是Uri类型,参数三为当前依赖属性的所属类,当前的类为PlaySoundAction,所以这个参数值就是这个,第四个参数为默认值,在此指定的为null,
    当然也可以自己进行指定。
    在属性Source的get访问器中通过GetValue方法得到依赖属性的值,通过SetValue方法对依赖属性赋值。
           //定义依赖属性
    public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(Uri),
    typeof(PlaySoundAction), new PropertyMetadata(null));

    public Uri Source
    {
    get { return (Uri)GetValue(PlaySoundAction.SourceProperty); }
    set { SetValue(PlaySoundAction.SourceProperty, value); }
    }


    接下来开始重写Invoke方法,其实这个方法很简单,就是创建一个MediaElement,然后指定Source属性,然后添加到调用方的容器中,就可以实现播放。

    其实真正的代码在FindContainer方法,该方法找到当前调用者(UIElement)所属的父容器,得到父容器,然后将MediaElement添加到该父容器即可,

    在这里有一个关键点就是VisualTreeHelper.GetParent,通过该方法得到传递UIElement的父容器(在此使用的是Panel,当然可以自行扩展),然后进行转换类型,至于VisualTreeHelper的具体用法,可以参见

    MSDN。

    得到了父容器之后,开始创建MediaElement,然后指定Source为我们定义的Source属性(通过在XAML中调用进行赋值得到指定的音频地址)的值,同时处理End事件和

    Failed事件,指定AutoPlay为自动播放,最后将MediaElement添加到父容器中,至此Action的工作已经告一段了,接下来看看如何在XMAL中具体的使用。

       protected override void Invoke(object parameter)
    {
    Panel container = FindContainer();

    if (container!=null)
    {
    MediaElement media = new MediaElement();
    media.Source = Source;
    media.MediaEnded += delegate
    {
    container.Children.Remove(media);
    };

    media.MediaFailed += delegate
    {
    container.Children.Remove(media);
    };

    media.AutoPlay = true;
    container.Children.Add(media);
    }
    }

    private Panel FindContainer()
    {
    //得到注册Action的Element
    FrameworkElement element = this.AssociatedObject;

    while (element != null)
    {
    if (element is Panel) return (Panel)element;
    element = VisualTreeHelper.GetParent(element) as FrameworkElement;
    }

    return (element != null) ? (Panel)element : null;
    }


    在Xaml中使用Action

    首先在Silverlight Application中对我们的Silverlight 类库进行dll的引用,这个不在赘述,然后在Xaml中对PlaySoundAction的namespace进行引用,同时还要对

    System.Windows.Interactivity.dll进行引用,引用如下:

    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:custom="clr-namespace:CustomerBehaviorLibrary;assembly=CustomerBehaviorLibrary"

    ok,引用工作也做完了,下面开始真正的调用,

    可以看到在此使用的是System.Windows.Interactivity下的Triggers,而并非Button.Triggers,然后还是创建一个EventTrigger,指定EventName为Click,最关键的异步,在EventTrigger中使用我们的PlaySoundAction,同时给Source属性赋值,至此所有代码已经完成,运行示例,点击按钮则会播放指定的音频文件,当然整个过程是没有在xaml.cs中写任何代码,同时这种方式还是通用的,可以在多个Xaml也买那使用这个Action,同时可以指定不同的Source。

            <StackPanel>
    <Button Height="25" Width="200" Content="Test SoundAction">
    <i:Interaction.Triggers>
    <i:EventTrigger EventName="Click">
    <custom:PlaySoundAction Source="/Baby.wma"></custom:PlaySoundAction>
    </i:EventTrigger>
    </i:Interaction.Triggers>
    </Button>
    </StackPanel>


    至此,一个简单的Action和Element的交互的工作已经完毕。


    上述的代码可以看到我们指定了当点击Button的Click时候触发这个Action,当然也可以指定其他的事件来触发这个Action,甚至我们可以在Action中指定哪个事件(每个UIElement的事件会有不同)来触发,看下边代码:

    可以看到我们给PlaySoundAction添加了几个DefaultTrigger这样的特性,解释下这几个参数,第一个就是指定的UIElement的类型,第二个当然也就是我们的事件触发器

    类型,第三个就是默认的事件了,可以看到第三个参数是一个数组的类型,当然也就是说可以给一个UIElement指定多个默认事件。

    有个亮点,由于Ellipse这样的Shape是没有Click事件的,所以我们需要指定其他的Mouse事件来替代,这就告诉我们要看具体的UIElement拥有的事件再来确定其默认事件。

        [DefaultTrigger(typeof(Button),typeof(System.Windows.EventTrigger),new object[]{"Click"}) ]
    [DefaultTrigger(typeof(Shape), typeof(System.Windows.EventTrigger), new object[] { "MouseEnter" })]
    [DefaultTrigger(typeof(UIElement), typeof(System.Windows.EventTrigger), new object[] { "MouseLeftButtonDown" })]
    public class PlaySoundAction : TriggerAction<FrameworkElement>
    {


    创建定向的Trigger(Targeted Trigger)

    在上边的例子中我们使用TriggerAction.AssociatedObject来得到整个UIElement,然后使用VisualTreeHelper得到其父容器。一些Action可以通过检索父容器来得到一些

    信息,但是有些Action需要获得不同的UIElement(可以通过一个UIElement调用一个Action来影响另一个Element),这时候就没法再使用TriggerAction这个类型,好在Silverlight中提供了TargetedTriggerAction类,这个类提供了Target属性,当然这个属性是需要在XAML中指定的TargetName属性(可以为使用者Element或者其他的UIElement的Name),下面看一个完整的例子,这个例子的功能就是将一个UIElement的Opacity使用动画的方式来修改(目标值为1)。

    首先需要定义一个附加属性DurationProperty表示动画的时间,同时定义一系列动画需要的StoryBoard和Animation;

    其次,重写Invoke方法,在这个方法中最重要的一句代码就是    Storyboard.SetTarget(fadeAnimation,this.Target);其中的this.Target就是TargetedTriggerAction和

    TriggerAction的最大区别(TargetedTriggerAction继承自TriggerAction类),这个属性就是要进行操作的目标对象。

    public class FadeInAction : TargetedTriggerAction<UIElement>
    {
    //定义一个附加属性,表示动画的时间长度
    private static readonly DependencyProperty DurationProperty =
    DependencyProperty.Register("Duration", typeof(TimeSpan), typeof(FadeInAction), new PropertyMetadata(TimeSpan.FromSeconds(0.2)));

    public TimeSpan Duration
    {
    get { return (TimeSpan)GetValue(DurationProperty); }
    set { SetValue(DurationProperty, value); }
    }

    //定义一个动画面板
    private Storyboard fadeStoryBoard = new Storyboard();
    //定义一个Double动画
    private DoubleAnimation fadeAnimation = new DoubleAnimation();

    public FadeInAction()
    {
    //将动画添加到动画面板中
    fadeStoryBoard.Children.Add(fadeAnimation);
    }
    ///<summary>
    /// 重写Invoke方法
    ///</summary>
    ///<param name="parameter"></param>
    protected override void Invoke(object parameter)
    {
    fadeStoryBoard.Stop();

    //设置动画Target为TargetedTriggerAction.Target属性
    Storyboard.SetTarget(fadeAnimation,this.Target);
    //设置动画的Property为Opacity
    Storyboard.SetTargetProperty(fadeAnimation,new PropertyPath("Opacity"));

    fadeAnimation.To = 1;
    fadeAnimation.Duration = Duration;
    fadeStoryBoard.Begin();
    }
    }



    看看在XAML中的调用方法:

    其实基本代码没有变化,只是在EventTrigger中指定的的Action指定了一个TargetName属性这个属性可以看到是另一个Board的Name属性,没错这个就是在Action中

    通过this.Target得到指定的UIElement的整个过程。

          <Button Height="25" Width="150" Content="Show Button By Action" HorizontalAlignment="Left">
    <i:Interaction.Triggers>
    <i:EventTrigger EventName="Click">
    <custom:FadeInAction TargetName="myBoard"></custom:FadeInAction>
    </i:EventTrigger>
    </i:Interaction.Triggers>
    </Button>
    <Border x:Name="myBoard" BorderBrush='Gray' Opacity="0.1" BorderThickness="2" Background="Green">
    <TextBlock FontSize="17" TextWrapping="Wrap" Text="I'm the target of the FadeOutAction and FadeInAction"></TextBlock>
    </Border>

    运行程序,当点击按钮Border的Opacity就会从初始值(0.1)变化到到1这个动画过程。







  • 相关阅读:
    玩转Android之手摸手教你DIY一个抢红包神器!
    NetWork——关于TCP协议的三次握手和四次挥手
    请保持心情快乐,请保持情绪稳定
    第八节:Task的各类Task<TResult>返回值以及通用线程的异常处理方案。
    第七节:利用CancellationTokenSource实现任务取消和利用CancellationToken类检测取消异常。
    第六节:深入研究Task实例方法ContinueWith的参数TaskContinuationOptions
    第五节:Task构造函数之TaskCreationOptions枚举处理父子线程之间的关系。
    第四节:Task的启动的四种方式以及Task、TaskFactory的线程等待和线程延续的解决方案
    第三节:ThreadPool的线程开启、线程等待、线程池的设置、定时功能
    第二节:深入剖析Thread的五大方法、数据槽、内存栅栏。
  • 原文地址:https://www.cnblogs.com/ListenFly/p/2253240.html
Copyright © 2011-2022 走看看