GVKun编程网logo

Silverlight之Styles和Behaviors(silver lights)

9

如果您对Silverlight之Styles和Behaviors和silverlights感兴趣,那么这篇文章一定是您不可错过的。我们将详细讲解Silverlight之Styles和Behaviors

如果您对Silverlight之Styles和Behaviorssilver lights感兴趣,那么这篇文章一定是您不可错过的。我们将详细讲解Silverlight之Styles和Behaviors的各种细节,并对silver lights进行深入的分析,此外还有关于How to attach behavior in code behind (Silverlight 3)、Silverlight - Attached Behavior + Command、Silverlight - Attached Behavior又一例 可复用的Storyboard Trigger、Silverlight 4 新特性之Silverlight as Drop Target的实用技巧。

本文目录一览:

Silverlight之Styles和Behaviors(silver lights)

Silverlight之Styles和Behaviors(silver lights)

本文简介

1.定义简单的Style

2.应用Style到元素

3.动态加载Style资源文件

4.Style的继承

5.组织内编写Style(在元素内)

6.自动应用Style到指定类型元素

7.Style绑定表达式

8.Behaviors的准备工作

9.创建Actions

10.在元素(Element)上使用Action

11.创建TargetedTriggerAction.

12.创建Behaviors

13.一些微软提供的Actions,Triggers,Behaviors

 

1.定义简单的Style

    <UserControl.Resources>
        <Style x:Key="redButtonStyle" targettype="Button">
            <Setter Property="Background" Value="Red"></Setter>
            <Setter Property="FontFamily" Value="宋体"></Setter>
            <Setter Property="FontSize" Value="14"></Setter>
        </Style>
    </UserControl.Resources>

Silverlight和css是完全不同的,通过Style标签定义,一个Style必须指定targettype(应用的元素的类型,当前是Button按钮),x:Key不是必须,当然如果你想让样式应用到所有指定类型的元素上,可以忽略x:Key,此处我们指定了Key,则要显示的使用。

 

2.是用Style到元素

<Button Content="14号字体按钮" Style="{StaticResource redButtonStyle}"></Button>

代码同样很简单,只需指定Stlye属性即可,属性值为静态资源中德redButtonStyle,即上述定义的样式。

 

3.动态加载Style资源文件

   右键Silverlight程序添加一个Dictionary文件即可,结构如下:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

</ResourceDictionary>

只有一个ResourceDictionary节点作为根节点,我们可以在里边添加很多个Style,如下:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Style x:Key="redButtonStyle" targettype="Button">
        <Setter Property="Background" Value="Red"></Setter>
    </Style>
    <Style x:Key="greenButtonStyle" targettype="Button">
        <Setter Property="Background" Value="Red"></Setter>
    </Style>
</ResourceDictionary>

Style的语法和上例子中的一样,不再赘述。定义好了资源文件,我们要进行动态加载,加载的地方就是StartUp,如下:

            ResourceDictionary testReourceDictionary = new ResourceDictionary();
            testReourceDictionary.source = new Uri("Dictionary1.xaml",UriKind.Relative);
            Application.Current.Resources.MergedDictionaries.Add(testReourceDictionary);

定义一个ResourceDictionary对象,设置属性Source为一个Uri,最终添加到Application.Current.Resources.MergedDictionaries,这样就可以在程序中的任意页面访问Key为"redButtonStyle"和"greenButtonStyle"了,使用方法和上述一致。
注意:此处必须注意,如果要动态加载资源文件,那么资源文件的输出类型(Output Type)必须为内容(Content),默认为页面(Page),所以此处要进行修改。

4.Style的继承

  有时候我们可能会重复写一些样式,此时可以将公共的部分提取出来作为一个BaseStyle,然后再添加一些继承其的Style。

    <Style x:Key="baseButtonStyle" targettype="Button">
        <Setter Property="FontSize" Value="12"></Setter>
        <Setter Property="Foreground" Value="Yellow"></Setter>
    </Style>
    <Style x:Key="redButtonStyle" targettype="Button" BasedOn="{StaticResource baseButtonStyle}">
        <Setter Property="Background" Value="Red"></Setter>
    </Style>
    <Style x:Key="greenButtonStyle" targettype="Button" BasedOn="{StaticResource baseButtonStyle}">
        <Setter Property="Background" Value="Red"></Setter>
    </Style>

注意:如果基样式的属性子样式中不存在,则会出现错误。

5.组织内编写Style(在元素内)

        <Button Content="A Customized Button">
            <Button.Style>
                <Style targettype="Button">
                    <Setter Property="FontFamily" Value="Georgia" />
                    <Setter Property="FontSize" Value="40" />
                    <Setter Property="Foreground" Value="White" />
                </Style>
            </Button.Style>
        </Button>

之前的例子都是将Style作为资源进行编写和访问,那样便于资源在多个地方进行使用,如果将Style写在元素的Style标签内,则Style只在本元素内有效,同时其优先级也最高。

 

6.自动应用Style到指定类型元素

  我们之前的代码中Style都指定了Key,当我们希望所有的targettype都应用样式的时候,忽略Key属性即可实现:

    <Style targettype="Button">
        <Setter Property="FontSize" Value="14"></Setter>
        <Setter Property="Foreground" Value="Gray"></Setter>
        <Setter Property="Margin" Value="10"></Setter>
    </Style>

上述Style并没有指定Key,同时指定了targettype为Button,那么所有的Button都将使用样式。

 

7.Style绑定表达式

 首先,可以在静态资源中使用使用表达式引用一个静态资源:

 

 <UserControl.Resources>
        <FontFamily x:Key="buttonFontFamily">Georgia</FontFamily>
        <sys:Double x:Key="buttonFontSize">18</sys:Double>
        <FontWeight x:Key="buttonFontWeight">Bold</FontWeight>
        <Style x:Key="BigButtonStyle1" targettype="Button">
            <Setter Property="FontFamily" Value="{StaticResource buttonFontFamily}" />
            <Setter Property="FontSize" Value="{StaticResource buttonFontSize}" />
            <Setter Property="FontWeight" Value="{StaticResource buttonFontWeight}" />
        </Style>
    </UserControl.Resources>

 其次,也可以定义为类方式访问,如下:

public class FontInfo
{
public FontFamily FontFamily { get; set; }
public double FontSize { get; set; }
public FontWeight FontWeight { get; set; }
}
    <UserControl.Resources>
        <local:FontInfo x:Key="buttonFont" FontFamily="Georgia" FontSize="18" FontWeight="Bold"></local:FontInfo>
        <Style x:Key="BigButtonStyle2" targettype="Button">
            <Setter Property="Padding" Value="20" />
            <Setter Property="Margin" Value="10" />
            <Setter Property="FontFamily" Value="{Binding Source={StaticResource buttonFont},Path=FontFamily}" />
            <Setter Property="FontSize" Value="{Binding Source={StaticResource buttonFont},Path=FontSize}" />
            <Setter Property="FontWeight" Value="{Binding Source={StaticResource buttonFont},Path=FontWeight}" />
        </Style>
    </UserControl.Resource

 

8.Behaviors的准备工作

 我们使用Style可以改变UI元素的一些外观,但是往往我们不仅仅如此的进行基本的设置。比如,缩放,拖动等功能,这样的代码复杂度要比业务代码复杂的多,当然它们也是通用的,所以这时候我们可以使用Behavior,将代码进行封装多处使用。

准备前奏,很遗憾的告诉大家Behavior本身是不存在Silverlight SDK中的,所以我们是无法直接创建它的,它的初衷是在Blend中,供设计时候使用,当然不代表我们无法在Silverlight中进行Behavior的开发

步骤如下:

 (1)下载Blend for Silverlight(下载)

 (2)安装Blend for Silverlight

 (3)早目录"c:\Program Files\Microsoft SDKs\Expression\Blend\Silverlight\v5.0\Libraries"下找到System.Windows.Interactivity.dll(提供Behavior功能的类库),Microsoft.Expression.Interactions.dll(包含了扩展的一些Behaviors)

 到这里准备工作完毕。

 9.创建Actions

   Action继承自TriggerAction<T>,通常情况下T为FrameworkElement(支持VisualTreeHelper操作)。接下来我们实现一个点击按钮播放音频的功能,首先新建一个Action如下:

    [DefaultTrigger(typeof(ButtonBase),typeof(i.EventTrigger),new object[] { "Click" })]
    [DefaultTrigger(typeof(Shape),new object[] { "MouseEnter" })]
    [DefaultTrigger(typeof(UIElement),new object[] { "MouseLeftButtonDown" })]
    public class PlaySoundAction : TriggerAction<FrameworkElement>
    {
        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); }
        }

        protected override void Invoke(object parameter)
        {
            Panel container = FindContainer();
            if (container != null)
            {
                MediaElement media = new MediaElement();
                media.source = this.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()
        {
            FrameworkElement element = this.Associatedobject;
            while (element != null)
            {
                if (element is Panel) return (Panel)element;
                element = VisualTreeHelper.GetParent(element) as FrameworkElement;
            }
            return null;
        }
    }

在类中添加了一个Uri类型的属性,用于设置MediaElement(该控件用于播放音频和视频,详情可查看MSDN),同时重写了TriggerAction<T>的Invoke,因为只要触发了Action,则会执行Invoke。在Invoke中我们创建了一个MediaElement并且将其放到页面的元素中,并开始播放。FindContainer方法用于找到当前页面的Panel容器(当前页面的为Grid,因为Grid的基类为Panel),在Invoke中将ModiaElement添加到查找到的Panel中。

注:使用TriggerAction.Associatedobject来得到整个UIElement。可以看到我们给PlaySoundAction添加了几个DefaultTrigger这样的特性,解释下这几个参数,第一个就是指定的UIElement的类型,第二个当然也就是我们的事件触发器类型,第三个就是默认的事件了,可以看到第三个参数是一个数组的类型,当然也就是说可以给一个UIElement指定多个默认事件。

 

10.在元素(Element)上使用Action

    新建一个UserControl,代码如下,添加Interactivity命名空间引用i,以及当前程序的命名空间引用local

<UserControl x:Class="SilverlightApplication2.MainPage"
    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:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:local="clr-namespace:SilverlightApplication2"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <Grid x:Name="LayoutRoot" Background="White">
        <Button Content="Click to play audio">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <local:PlaySoundAction Source="潘裕文-夏雨诗.mp3"></local:PlaySoundAction>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
    </Grid>
</UserControl>

在按钮中添加了Triggers并且指定事件为Click,然后使用了我们的PlaySoundAction,同时指定了Source为一个媒体文件(必须注意,必须将文件的Output Type也就是输出类型选择为Resource资源,这样才可以访问的到)。现在运行程序是不是就可以听到优美的歌声了呢。

11.创建TargetedTriggerAction

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

/// <summary>
    /// 使Opacity渐变到0
    /// </summary>
    public class FadeOutAction : TargetedTriggerAction<UIElement>
    {
        public static readonly DependencyProperty DurationProperty =
        DependencyProperty.Register("Duration",typeof(TimeSpan),typeof(FadeOutAction),new PropertyMetadata(TimeSpan.FromSeconds(2)));
        public TimeSpan Duration
        {
            get { return (TimeSpan)GetValue(FadeOutAction.DurationProperty); }
            set { SetValue(FadeOutAction.DurationProperty,value); }
        }
        private Storyboard fadeStoryboard = new Storyboard();
        private DoubleAnimation fadeAnimation = new DoubleAnimation();
        public FadeOutAction()
        {
        }
        protected override void Invoke(object args)
        {
            fadeStoryboard.Stop();

            Storyboard.SetTarget(fadeAnimation,this.Target);
            Storyboard.SetTargetProperty(fadeAnimation,new PropertyPath("Opacity"));

            fadeAnimation.To = 0;
            fadeAnimation.Duration = Duration;
            fadeStoryboard.Begin();
        }
    }
    /// <summary>
    /// 使Opacity渐变到1
    /// </summary>
    public class FadeInAction : TargetedTriggerAction<UIElement>
    {
        // The default fade in is 0.5 seconds.
        public static readonly DependencyProperty DurationProperty =
        DependencyProperty.Register("Duration",typeof(FadeInAction),new PropertyMetadata(TimeSpan.FromSeconds(0.5)));
        public TimeSpan Duration
        {
            get { return (TimeSpan)GetValue(FadeInAction.DurationProperty); }
            set { SetValue(FadeInAction.DurationProperty,value); }
        }
        private Storyboard fadeStoryboard = new Storyboard();
        private DoubleAnimation fadeAnimation = new DoubleAnimation();
        public FadeInAction()
        {
            fadeStoryboard.Children.Add(fadeAnimation);
        }
        protected override void Invoke(object args)
        {
            fadeStoryboard.Stop();
            Storyboard.SetTarget(fadeAnimation,new PropertyPath("Opacity"));
            fadeAnimation.To = 1;
            fadeAnimation.Duration = Duration;
            fadeStoryboard.Begin();
        }
    }

首先需要定义一个附加属性DurationProperty表示动画的时间,同时定义一系列动画需要的StoryBoard和Animation;
其次,重写Invoke方法,在这个方法中最重要的一句代码就是 Storyboard.SetTarget(fadeAnimation,this.Target);
其中的this.Target就是TargetedTriggerAction和TriggerAction的最大区别(TargetedTriggerAction继承自TriggerAction类),这个属性就是要进行操作的目标对象。

Xaml代码如下:

<StackPanel>
        <StackPanel Orientation="Horizontal" Margin="3,15">
            <Button Content="Click to Fade the TextBlock" Padding="5">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                        <local:FadeOutAction TargetName="border" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Button>
            <Button Content="Click to Show the TextBlock" Padding="5">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                        <local:FadeInAction TargetName="border" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Button>
        </StackPanel>
        <Border x:Name="border" Background="Orange" BorderBrush="Black" BorderThickness="1" Margin="3,0" >
            <TextBlock Margin="5" FontSize="17" textwrapping="Wrap" Text="I'm the target of the FadeOutAction and FadeInAction."></TextBlock>
        </Border>
    </StackPanel>

和上个例子中没有太多变化,唯一区别就是TargetName的设置,通过设置TargetName为Border,这样在Action中的this.Target就可以得到要操作的对象。运行例子,点击
第一个按钮文本则会逐渐消失,点击第二个按钮则会逐渐显示。
注:两个类分别用于Opacity的相反效果。

12.创建Behaviors

 大家经常会把Action形容为Behavior,Action单独是无法进行使用的,需要结合Trigger才能使元素进行操作。Behavior的目标是让XAML的代码更加的精简,或者说Behavior  其实是组合了Action和Trigger,XAML无需Code即可实现操作,同时Behavior可以实现代码的通用性。

选择Action还是选择Behavior?如果您试图创建共享数据操作或交互或者需要你行为和具体行为之间紧密耦合,你应该考虑实现自己功能一个行为。

创建一个Behavior如下(用于实现拖拽元素到Canvas):

 自定义的Behavior的基类为Behaviror<T>,其中需要重写OnAttachmented和OnDetaching,触发前者的时候可以操作应用Behavior的元素并且可以给其添加事件;在后者事件触发的时候可以做清理工作以及对元素进行事件的移除。

 public class DragInCanvasBehavior : Behavior<UIElement>
    {
        private Canvas canvas;

        protected override void OnAttached()
        {
            base.OnAttached();
            this.Associatedobject.MouseLeftButtonDown += Associatedobject_MouseLeftButtonDown;
            this.Associatedobject.MouseMove += Associatedobject_MouseMove;
            this.Associatedobject.MouseLeftButtonUp += Associatedobject_MouseLeftButtonUp;
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            this.Associatedobject.MouseLeftButtonDown -= Associatedobject_MouseLeftButtonDown;
            this.Associatedobject.MouseMove -= Associatedobject_MouseMove;
            this.Associatedobject.MouseLeftButtonUp -= Associatedobject_MouseLeftButtonUp;
        }

        // 元素是否正在被拖拽
        private bool isDragging = false;
        // 记录下元素的鼠标原始位置
        private Point mouSEOffset;

        private void Associatedobject_MouseLeftButtonDown(object sender,MouseButtonEventArgs e)
        {
            // 查找到Canvas
            if (canvas == null) canvas = VisualTreeHelper.GetParent(this.Associatedobject) as Canvas;
            // 标识正在拖拽
            isDragging = true;
            // 得到鼠标位置
            mouSEOffset = e.GetPosition(Associatedobject);
            // 设置当前操作的鼠标位置为该元素
            Associatedobject.CaptureMouse();
        }

        private void Associatedobject_MouseMove(object sender,MouseEventArgs e)
        {
            if (isDragging)
            {
                // 鼠标移动中,动态得到位置
                Point point = e.GetPosition(canvas);
                // 修改元素的坐标位置
                Associatedobject.SetValue(Canvas.TopProperty,point.Y - mouSEOffset.Y);
                Associatedobject.SetValue(Canvas.LeftProperty,point.X - mouSEOffset.X);
            }
        }

        private void Associatedobject_MouseLeftButtonUp(object sender,MouseButtonEventArgs e)
        {
            if (isDragging)
            {
                //释放鼠标
                Associatedobject.ReleaseMouseCapture();
                //标识为未拖拽
                isDragging = false;
            }
        }
    }

XAML使用如下:

 <Canvas>
        <Rectangle Canvas.Left="10" Canvas.Top="10" Fill="Yellow" Width="40" Height="60">
        </Rectangle>
        <Ellipse Canvas.Left="10" Canvas.Top="70" Fill="Blue" Width="80" Height="60">
            <i:Interaction.Behaviors>
                <local:DragInCanvasBehavior></local:DragInCanvasBehavior>
            </i:Interaction.Behaviors>
        </Ellipse>
        <Ellipse Canvas.Left="80" Canvas.Top="70" Fill="OrangeRed" Width="40" Height="70">
            <i:Interaction.Behaviors>
                <local:DragInCanvasBehavior></local:DragInCanvasBehavior>
            </i:Interaction.Behaviors>
        </Ellipse>
    </Canvas>

一共三个图形,其中Rectangle没有使用Behavior,所以它是不能够拖动的,而另外两个Ellipse指定了Behaviros则可以实现拖动的效果,好了赶紧运行的代码见证神奇的一刻。

13.一些微软提供的Actions,Triggers,Behaviors

上述我们都是自己在做一些Action和Behavior,当然微软已经提供了一些比较实用的类库(他们都藏在Microsoft.Expression.Interactions.dll中),详细如下:

Action:
ChangePropertyAction,GoToStateAction,HyperlinkAction,RemoveElementAction

Triggers:
KeyTrigger,TimerTrigger,StoryboardCompletedTrigger

Behaviors:
MouseDragElementBehavior,FluidMoveBehavior

具体的使用方法,大家可以参考MSDN解释。(可以访问http://expressionblend.codeplex.com,http://gallery.expression.microsoft.com.获得更多的支持)

 到这里本文的讲解就结束了,希望大家多提意见和建议,欢迎多多交流。

How to attach behavior in code behind (Silverlight 3)

How to attach behavior in code behind (Silverlight 3)

For those of you who would like to add (attach) behavior to control in code behind,there is a simple solution.

Adding Behaviors

Let's say that we have xaml code like this one:

 

<TextBox x:Name="TextBoxInvoker" Text="TextBoxControl"  >

     <i:Interaction.Behaviors>

          <behavior:TextBoxSimpleBehavior />

     </i:Interaction.Behaviors>

</TextBox>

,where "i:" is a namespace for "clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" and "behavior:" is a namespace for behavior's class "TextBoxSimpleBehavior",which  can be simple class like this one (just adding typed letters to content):

using System;

using System.Net;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Ink;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

using System.Windows.Interactivity;

 

/// Dummy  sample behavior for TextBox control.

/// It add extra letter in the end of Text property.

/// <author>

/// Jacek Ciereszko

/// http://geekswithblogs.net/SilverBlog/

/// </author>

 

namespace TextBoxEnterBehavior

{

    public class TextBoxSimpleBehavior : Behavior<TextBox>

    {

        public TextBoxSimpleBehavior() : base() { }

 

        /// <summary>

        /// Called after the Behavior is attached to an Associatedobject.

        /// </summary>

        /// <remarks>Override this to hook up functionality to the Associatedobject.</remarks>

        protected override void OnAttached()

        {

            base.OnAttached();

            this.Associatedobject.KeyDown += new KeyEventHandler(Associatedobject_KeyDown);

        }

 

        /// <summary>

        /// Called after the Behavior is detached from an Associatedobject.

        /// </summary>

        /// <remarks>Override this to hook up functionality to the Associatedobject.</remarks>

        protected override void OnDetaching()

        {

            base.OnDetaching();

            this.Associatedobject.KeyDown += new KeyEventHandler(Associatedobject_KeyDown);

        }

 

        /// Simple operation on TextBox

        void Associatedobject_KeyDown(object sender,KeyEventArgs e)

        {

            this.Associatedobject.Text += e.Key;

        }

 

    }

}

 

So,to do the same operation in code behind,write:

// Adding behavior in code behind

TextBoxSimpleBehavior textBoxSimpleBehavior = new TextBoxSimpleBehavior();

            System.Windows.Interactivity.Interaction.GetBehaviors(TextBoxInvoker).Add(textBoxSimpleBehavior);

Adding Triggers

In this example I will use my TargetedTriggerAction from prevIoUs post http://geekswithblogs.net/SilverBlog/archive/2009/09/21/behaviors-textbox-enter-button-invoke-targetedtriggeraction.aspx
In xaml I attached my TriggerAction using this code:

<Button x:Name="TargetedButton" Content="Targeted Button"  />

<TextBox x:Name="TextBoxInvoker" Text="TextBox" >

    <i:Interaction.Triggers>

        <i:EventTrigger EventName="KeyDown" >

            <behavior:TextBoxEnterButtonInvoke TargetName="TargetedButton" />

        </i:EventTrigger>

    </i:Interaction.Triggers>

</TextBox>

where "i:" is a namespace for "clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" and "behavior:" is a namespace for behavior's code.

In code behind I will write this code:

// Adding TriggerAction in code behind

TextBoxEnterButtonInvoke textBoxEnterButtonInvoke = new TextBoxEnterButtonInvoke();

textBoxEnterButtonInvoke.TargetName = "TargetedButton";

 

System.Windows.Interactivity.EventTrigger eventTrigger = new System.Windows.Interactivity.EventTrigger("KeyDown");

eventTrigger.Actions.Add(textBoxEnterButtonInvoke);

 

System.Windows.Interactivity.Interaction.GetTriggers(TextBoxInvoker).Add(eventTrigger);

Done! That's all we need to attach behaviors in code behind.

Silverlight - Attached Behavior + Command

Silverlight - Attached Behavior + Command

CAL (Prism)中的Command绑定非常好用,可以将某个button的click事件绑定到viewmodel中的某个方法上,简单明了。但是,

 

CAL (Prism)中的Commands对Silverlight的支持有一个限制 ,只实现了对ButtonBase的Click事件的Command Binding:


The command support in Silverlight is built using an attached behavior pattern. This pattern connects events raised by controls to code on a Presenter or PresentationModel. In WPF and Silverlight,an attached behavior is comprised of two parts: an attached property and a behavior object. The attached property establishes a relationship between the target control and the behavior object. The behavior object monitors the target control and takes action based on events or state change in the control. For example,the Composite Application Library provides an attached behavior that executes commands from the Click event of ButtonBase.

 

对其他控件中的事件则需要自己来实现:

 

Frequently,applications need to invoke commands from controls or events other than the Click event from ButtonBase . In these cases,you need to define your own attached property and behavior. The Composite Application Library provides a CommandBehaviorBase <T> to make it easier to create behaviors that interact with ICommands . This class invokes the command and monitors changes in the command's CanExecuteChanged event,and can be used to extend command support in both Silverlight and WPF.

To create your custom behavior,create a class that inherits from CommandBehaviorBase <T> and targets the control you want to monitor. In the constructor of your class,you will need to subscribe to the events you want to monitor from the control.

 

这个实现其是Attached Behavior 与 CAL (Prism)中Command的一个结合。这里有一个例子

 

关于Attached Behavior

Silverlight - Attached Behavior又一例 可复用的Storyboard Trigger

Silverlight - Attached Behavior又一例 可复用的Storyboard Trigger

Silverlight中Attached Behavior 的应用场景很多,比如前面提到过的Attached Command 。Silverlight中实现某个动画,一般会在Xaml的code behind中去触发Storyborad.Begion来启动动画。但是这样的动画复用性就很差。这篇blog 给出了一种方案,可复用动画触发的逻辑,同样是利用Attached Behavior来实现的

Silverlight 4 新特性之Silverlight as Drop Target

Silverlight 4 新特性之Silverlight as Drop Target

在上次项目中写过多篇关于拖拽的实现. 这些拖拽都是控件之间的效果. Silverlight 4 中我们甚至可以直接把文件系统中文件拖拽到Silverlight Application中承载. 这就是 silverlight 4中新特性Silverlight As Drop Target 支持这一点. 为了达到演示目的. 使用桌面图片拖拽到Silverlight Application中ScrollViewer动态显示. 先体验一下[你可以尝试从本地文件系统直接拖拽图片到这个Silverlight Application中看一下效果]:

实现步骤:

<1>: 页面布局

 
 
  1. <StackPanel x:Name="LayoutRoot" Background="White">  
  2.          <TextBlock Text="  "></TextBlock>  
  3.          <TextBlock Text="Silverlight AS Drop target.-chenkai[10.6.28]" VerticalAlignment="Center" HorizontalAlignment="Left" FontSize="16" Foreground="Red"  FontFamily="Comic Sans MS" FontWeight="BOld" Height="25" Width="655" />  
  4.          <ScrollViewer x:Name="ImagesTarget" Background="White"  Height="360" BorderBrush="Red" 
  5.                        VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Auto" AllowDrop="True">  
  6.                  <ItemsControl x:Name="ImageList" Height="353">  
  7.                      <!--定义数据模板 支持格式是Image图片 很重要 不然会包invaid异常 数据模板确实很强大.-->  
  8.                      <ItemsControl.ItemTemplate>  
  9.                          <DataTemplate>  
  10.                              <Image Source="{Binding}" Margin="5" Stretch="UniformToFill" Height="240" />  
  11.                          </DataTemplate>  
  12.                      </ItemsControl.ItemTemplate>  
  13.                      <!--项排序模式Horizontal 居中-->  
  14.                      <ItemsControl.ItemsPanel>  
  15.                          <ItemsPanelTemplate>  
  16.                              <StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center"/>  
  17.                          </ItemsPanelTemplate>  
  18.                      </ItemsControl.ItemsPanel>  
  19.                  </ItemsControl>  
  20.              </ScrollViewer>  
  21.      </StackPanel> 

<2>:后台实现代码

 
 
  1. //定义存储Image集合.  
  2.          ObservableCollection<BitmapImage> _images = new ObservableCollection<BitmapImage>();  
  3.    
  4.          public MainPage()  
  5.          {  
  6.              InitializeComponent();  
  7.              this.Loaded += new RoutedEventHandler(MainPage_Loaded);  
  8.          }  
  9.    
  10.          void MainPage_Loaded(object sender, RoutedEventArgs e)  
  11.          {  
  12.              //如果Image数据则直接加载进来.  
  13.              ImageList.ItemsSource = _images;  
  14.              ImagesTarget.Drop += new DragEventHandler(ImagesTarget_Drop);  
  15.          }  
  16.          void ImagesTarget_Drop(object sender, DragEventArgs e)  
  17.          {  
  18.              //判断拖拽数据是否存在  
  19.              if (e.Data == null)  
  20.              {  
  21.                  return;  
  22.              }  
  23.              else 
  24.              {  
  25.                  //利用Fileinfo 来初始化关于文件系统日常操作io对象 Fileinfo 【】数组 意味支持多张Image同时拖拽Silverlight Application  
  26.                  IDataObject dataObject = e.Data as IDataObject;  
  27.                  FileInfo[] files =dataObject.GetData(DataFormats.FileDrop) as FileInfo[];  
  28.    
  29.                  foreach (FileInfo file in files)  
  30.                  {  
  31.                      try  
  32.                      {  
  33.                          using (var stream = file.OpenRead())  
  34.                          {  
  35.                              //读取拖拽中图片源.  
  36.                              var imageSource = new BitmapImage();  
  37.                              imageSource.SetSource(stream);  
  38.                              //添加到集合中.  
  39.                              _images.Add(imageSource);  
  40.                          }  
  41.                      }  
  42.                      catch (Exception)  
  43.                      {  
  44.                          MessageBox.Show("Not a suppoted image.");  
  45.                      }  
  46.                  }  
  47.              }  
  48.          }  

因为前台ScrollView中DataTemplate中定义格式是Image绑定. 后台数据源用到ObservableCollection<BitmapImage>来封装从拖拽中得到图片数据. 另外一个就是FileInfo,提供创建、复制、删除、移动和打开文件的实例方法,并且帮助创建 FileStream 对象,既然通过Fileinfo得到FileStream对象 其他操作就是平常IO操作. 而Fileinfo[]数组则是用来支持同时拖拽多个对象.关于Fileinfo 更多详细资料请参见MSDN.

关于Silverlight之Styles和Behaviorssilver lights的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于How to attach behavior in code behind (Silverlight 3)、Silverlight - Attached Behavior + Command、Silverlight - Attached Behavior又一例 可复用的Storyboard Trigger、Silverlight 4 新特性之Silverlight as Drop Target等相关知识的信息别忘了在本站进行查找喔。

本文标签: