本文简介

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), typeof(i.EventTrigger), new object[] { "MouseEnter" })]
[DefaultTrigger(typeof(UIElement), typeof(i.EventTrigger), 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()));
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 = ;
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(TimeSpan),
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, this.Target);
Storyboard.SetTargetProperty(fadeAnimation, new PropertyPath("Opacity"));
fadeAnimation.To = ;
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.获得更多的支持)

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

Silverlight之Styles和Behaviors的更多相关文章

  1. WPF之Behavior

    本文主要是以实现拖动元素作为例子. 创建Behavior: 通常这个类会继承自Behavior<T>,其中T就是此Behavior服务的对象,在此处使用的是UIElement,也就是虽有的 ...

  2. 20 Interesting WPF Projects on CodePlex

    20 Interesting WPF Projects on CodePlex (Some for Silverlight too) Pete Brown - 22 November 2010   I ...

  3. 从 Bootstrap 2.x 版本升级到 3.0 版本

    摘自http://v3.bootcss.com/migration/ Bootstrap 3 版本并不向后兼容 v2.x 版本.下面的章节是一份从 v2.x 版本升级到 v3.0 版本的通用指南.如需 ...

  4. 补充:学会Twitter Bootstrap不再难

    博客园的兄弟姐妹们很给力,自从这篇文章写出后,有人可能会对2.x版本升级到3.x版本的区别有些好奇和模糊.现在将官方给出的说明贴上去: 从2.x升级到3.0版本 Bootstrap 3并不向后兼容Bo ...

  5. Bootstrap 简洁、直观、强悍、移动设备优先的前端开发框架,让web开发更迅速、简单。

    http://v3.bootcss.com/ 从2.x升级到3.0版本 Bootstrap 3并不向后兼容Bootstrap v2.x.下面章节列出的内容可以作为从v2.x升级到v3.0的通用指南.如 ...

  6. 自定义SharePoint2013 master page

    SharePoint uses templates to define and render the pages that a site displays. The structure of a Sh ...

  7. Motion Paths in WPF 4 using Expression Blend 4

    原文 Motion Paths in WPF 4 using Expression Blend 4 Posted by: Pravinkumar Dabade , on 3/19/2011, in C ...

  8. Prism 4 文档 ---第10章 Silverlight和WPF之间共享代码

        本主题帮助你理解来自Prism的多目标和它的优缺点.多目标的代码针对两个不同的平台有大致相同的代码库.这允许同时保持代码尽可能多一样能够产生针对两种不同技术的二进制文件.在这种情况下,本节介绍 ...

  9. Silverlight behavior(行为) trigger 大全

    behavior是超级有用的东西,一定要学会,因为这个就是面向对象编程中的封装.超级重要! 欢迎大家如果有好的效果,可以给我留言,我打算不断的整理这个behavior,希望不久用behavior可以做 ...

随机推荐

  1. JS基础类型和对象,分别是按值传递还是按引用传递?

    在分析这个问题之前,我们需了解什么是按值传递(call by value),什么是按引用传递(call by reference).在计算机科学里,这个部分叫求值策略(Evaluation Strat ...

  2. [Interview][CodingExam]

    這次去Interview, 其中有一個公司 把我列為 2/25的考慮對象, 在Final 的 1/2, 我被刷掉了. 因為第一輪的程式,我稍微google了一下,參考了既有的寫法. 即使第二輪我用完全 ...

  3. 通过 SuperObject 生成 json string

    (* { "name": "Henri Gourvest", /* this is a comment */ "vip": true, &q ...

  4. 文件大小的友好输出及其 Python 实现

    在数据库中存储时,使用 Bytes 更精确,可扩展性和灵活性都很高. 输出时,需要做一些适配. 1. 注意事项与测试代码 需要考虑 sizeInBytes 为 None 的场景. 除以 1024.0 ...

  5. Microsoft Visual Studio Ultimate 2012 旗舰版 有效注册密钥

    Microsoft Visual Studio Ultimate 2012 旗舰版 有效注册密钥: YKCW6-BPFPF-BT8C9-7DCTH-QXGWC 已经过本人测试 本着分享的精神,希望大家 ...

  6. Eclipse中propedit插件安装(解决property中文问题)

    Eclipse Help--Install New Software... Add... propedit   -- http://propedit.sourceforge.jp/eclipse/up ...

  7. 跨域解决方案CORS使用方法

    CORS(Cross-Origin Resource Sharing), 目前CORS还处于w3c的草案,它定义了跨域访问时服务器和客户端之间如何通信.他的原理是通过定义HTTP头部的信息,来让客户端 ...

  8. HTML 背景图片自适应

    CSS body.loginpage { background-image: url(../images/background-image.jpg); background-size:cover; } ...

  9. 详解C#中的反射(转载)

    反射(Reflection) 2008年01月02日 星期三 11:21 两个现实中的例子: 1.B超:大家体检的时候大概都做过B超吧,B超可以透过肚皮探测到你内脏的生理情况.这是如何做到的呢?B超是 ...

  10. Unity3d读取.csv文件

    原文地址:http://blog.csdn.net/dingkun520wy/article/details/26594991 (一)文件路径 需要把csv文件放在StreamingAssets这个文 ...