Experience10  Creative, Develop, UX, Wireframe, Productivity

#Silverlight

[翻译]Part&States Model With VisualStateManager(3/4)

[原文地址]
这是系列教程的第三篇.

上一次,你学会了如何对现有的控件使用VisualStateManager来改变皮肤外观.在这一篇中,你会看到如何创建基于"部件"与"状态"的自定义控件.同时我们还会探索创建一些更精密复杂的视觉过渡效果.

视觉状态管理器VisualStageManger

在上一篇中我们曾简述过,但现在我们正式的介绍VisualStageManager视觉状态管理器

VisualStateManager是一个类,用来管理控件的视觉状态."Visual"是关键字(用来管理视觉,非逻辑)-控件的逻辑仍然只负责逻辑状态.

VSM暴露PME的二个片段:

  • 一个VisualStageGroups attached property(附加属性)

    • 这个属性放在控件模板的RootVisual并包含所有与外观有关的视觉状态与过渡效果

  • 一个静态GoToStage()方法

    • 这个方法的产生原因是因为VisualStageManager需要来控制控件的视觉由一个视觉状态过渡到其它状态

上一次,我们专注于XAML中的VisualStageGroups属性.今天,我们深入到控件的代码中的GoToStage()方法.

WeatherControl

我们今天会来看一个简单的自定义控件 WeatherControl. 控件的部分代码可以在下面看到.(注意:为了可读性,我折叠了一些代码片段,你可以从这里找到完整的代码.)

public class WeatherControl : Control{public WeatherControl(){DefaultStyleKey = typeof(WeatherControl);}// OnApplyTemplate()public override void OnApplyTemplate(){base.OnApplyTemplate();}// Temperature DPpublic static readonly DependencyProperty TemperatureProperty = DependencyProperty.Register("Condition", typeof(Condition), typeof(WeatherControl), null);public string Temperature{get { /*…*/ }set { /*…*/ }}// Condition DP public static readonly DependencyProperty ConditionProperty = DependencyProperty.Register("Condition", typeof(Condition), typeof(WeatherControl), new PropertyMetadata(new PropertyChangedCallback(WeatherControl.OnConditionPropertyChanged)));public Condition Condition{get {  /*…*/ }set { /*…*/ }}// ConditionDescription DP public static readonly DependencyProperty ConditionDescriptionProperty = DependencyProperty.Register("ConditionDescription", typeof(string), typeof(WeatherControl), null);public string ConditionDescription{get {  /*…*/ }set { /*…*/}}// Property change notification  private static void OnConditionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){WeatherControl weather = d as WeatherControl;//…  weather.OnWeatherChange(null);}// OnWeatherChange virtual  protected virtual void OnWeatherChange(RoutedEventArgs e){ }}

你可以看看我们的WeatherControl…

  • 是一个自定义控件,继承自Control.
  • 定义内置Style,并由DefaultStyleKey来标识.
  • 有三个公共的依赖属性dependency properties:

    • Temperature
    • Condition
    • ConditionDescription

如果让我们的WeatherControl能够使用VSM来换皮肤,我们需要:

  • 定义一个控件约定
  • 找到和操作parts部件
  • 使用VisualStageManager来接管合适的状态

Here we go!

定义控件约定

控件的代码负责描述控件的约定.意味着必须声明任意和所有的期望出现的部件(Parts)与状态(Stages).这是使用metadata完成的在类中的声明:

[TemplatePart(Name="Core", Type=typeof(FrameworkElement))][TemplateVisualState(Name="Normal", GroupName="CommonStates")][TemplateVisualState(Name="MouseOver", GroupName="CommonStates")][TemplateVisualState(Name="Pressed", GroupName="CommonStates")][TemplateVisualState(Name="Sunny", GroupName="WeatherStates")][TemplateVisualState(Name="PartlyCloudy", GroupName="WeatherStates")][TemplateVisualState(Name="Cloudy", GroupName="WeatherStates")][TemplateVisualState(Name="Rainy", GroupName="WeatherStates")]public class WeatherControl : Control {…  }

在上面的片段中,有二个attribute类:

  • TemplatePartAttribute

    • 指定部件名称与期望的类型

  • TemplateVisualStateAttribute

    • 指定状态和他所属的状态组的名称

这些metadata并不是实时调用的.但他能被Expression Blend工具识别(以用于可视化编辑的支持).

这些在WeatherControl上的attributes给了控件下列的内容:

现在,我们来看看如何编写部件的操作代码.

找到部件

被命名的部件需要在控件代码中手动编写代码来找到相应的部件.这个操作在OnApplyTemplate()这个虚方法中执行当一个template被应用时.

// OnApplyTemplate   public override void OnApplyTemplate()   {  base.OnApplyTemplate(); CorePart = (FrameworkElement)GetTemplateChild("Core");  }   // private CorePart property  private FrameworkElement CorePart  {  get  {  return corePart; }  set  {  FrameworkElement oldCorePart = corePart; if (oldCorePart != null) { oldCorePart.MouseEnter -= new MouseEventHandler(corePart_MouseEnter); oldCorePart.MouseLeave -= new MouseEventHandler(corePart_MouseLeave);  oldCorePart.MouseLeftButtonDown -= new MouseButtonEventHandler(corePart_MouseLeftButtonDown);  oldCorePart.MouseLeftButtonUp -= new MouseButtonEventHandler(corePart_MouseLeftButtonUp); }  corePart = value; if (corePart != null) {  corePart.MouseEnter += new MouseEventHandler(corePart_MouseEnter);  corePart.MouseLeave += new MouseEventHandler(corePart_MouseLeave); corePart.MouseLeftButtonDown += new MouseButtonEventHandler(corePart_MouseLeftButtonDown); corePart.MouseLeftButtonUp += new MouseButtonEventHandler(corePart_MouseLeftButtonUp); } }  }

你需要使用GetTemplateChild() 这个helper方法来找到模板中的被命名元素.

在上面的例子中,我们找到了"Core"部件,这是一个我们会用于确定当控件引发MouseOver或Pressed状态时的部件.值得注意的是setter访问器的逻辑声明并不是在template中声明的.这很重要,因为控件需要足够健全以便于当某个部件在template中没有时也能够正常工作.

初始化状态改变

控件代码负责向VisualStateManager告之什么时候状态改变.因此,代码必须维护着logical state machine与visual state machine的状态.

所有Silverlight 2的内置控件都创建了简单的helper方法去辅助状态变化.我们推荐你使用这个简单的模式:

// GoToState() helper private void GoToState(bool useTransitions)  {  //  Go to states in NormalStates state group if (isPressed)   {   VisualStateManager.GoToState(this, "Pressed", useTransitions);  }  else if (isMouseOver) {  VisualStateManager.GoToState(this, "MouseOver", useTransitions); }  else {  VisualStateManager.GoToState(this, "Normal", useTransitions);                 } //  Go to states in WeatherStates state group  if (Condition ==  Condition.PartlyCloudy)  { VisualStateManager.GoToState(this, "PartlyCloudy", useTransitions); } else if (Condition == Condition.Sunny) { VisualStateManager.GoToState(this, "Sunny", useTransitions); } else if (Condition == Condition.Cloudy) { VisualStateManager.GoToState(this, "Cloudy", useTransitions); }  else  {  VisualStateManager.GoToState(this, "Rainy", useTransitions); }  }

GoToStage helper方法包含几个用于确定当前视觉状态的语法.他告诉VisualStateManager去初始化合适的状态变化.然后调用静态方法

public static bool VisualStateManager.GoToState(Control control, string stateName, bool useTransitions)

就像你所看到的,这个方法中…

  • 有三个参数:

    • control: 控件的实例
    • stateName: 要去的视觉状态的名称
    • usetTransitions: 确定正在进行过渡效果的一个标记

  • 返回一个 bool 型

    • 如果状态名找到就返回true,返之则false.

  • 无法满足if条件的情况…

    • 控件在处于发生过的visual state下
    • visual state无法找到

大部分控件作者会在三个情况下调用GoToStage() helper

  • OnApplyTemplate() 没有任何过渡效果

    • 当控件第一次呈现,我们会呈现在合适的状态下,并没有任何过渡效果加于上面.

  • 在确定的属性通知Handler中
  • 在确定的事件Handler中

在我们的WeatherControl中,我们添加以下调用:

// OnApplyTemplate public override void OnApplyTemplate() {  base.OnApplyTemplate(); CorePart = (FrameworkElement)GetTemplateChild("Core");  GoToState(false);   }  // Property Change Notifications  protected virtual void OnWeatherChange(RoutedEventArgs e)  {  GoToState(true);         } // Event Handlers void corePart_MouseEnter(object sender, MouseEventArgs e) { isMouseOver = true; GoToState(true); }  void corePart_MouseLeave(object sender, MouseEventArgs e) {  isMouseOver = false; GoToState(true);  }  void corePart_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)  { isPressed = true;  GoToState(true);}  void corePart_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)  {  isPressed = false;GoToState(true); }

我们在下面情况时,需要初始化状态变化:

  • 模板被初次应用
  • 条件属性变化
  • 鼠标事件在由Core部件激发

添加内置Style

现在我们看看我们的控件逻辑!

我使我们的ControlTemplate变得非常有趣,有趣意味着模板会变得冗长..不管怎样,看看编辑后的版本:

                   :

你可以看到ControlTemplate中,我做了:

  • 定义了7个VisualStates:
  • 定义了storyboard资源来声明状态的storyboard
  • 提供一个默认的VisualTransition,用于CommonStages和WeatherStates
  • 指定了VisualTransitions,用于CommonStages的certain stage changes

我们来运行一下!

添加专门的过渡效果Transitions

默认的过渡效果还可以.但,为了做得更好,我们加一些更多的自定义的视觉过渡效果.

下面是我们在不同weather状态下的不同外观:

当我们的控件从Sunny变为PartlyCloudy时,我们不想让云层效果慢慢动画过来,替代方法是,让他从左边进来.

为了让自定义的过渡效果像这个一样,你可以声明一个详细的过渡故事板:

  

现在,当VisualStateManager为Sunny到PartlyCloudy状态变化生成动画时,不会花很长时间产生BottomCloud的透明度动画.会马上运行我们定义的这个详细的故事板动画.

为了更好的理解生成动画与详细故事板之间的作用关系,我们看下面的示例:

这里,我们有二个视觉状态:Foo & Bar.每一个动画有一个不同的属性.

这些动画是如何创建的?

  • VSM会生成属性A,C和D之间的过渡动画

    • A,C和D会在一个或二个状态间发生动画,并且不会执行VisualTransition.Storyboard下定义的详细故事板

  • VSM会根据详细故事板运行B,E和G之间的动画

    • B,E和G会根据VisualTransition.Storyboard来动画.VSM不会自动为这些属性生成动画.

  • VSM不会为属性F生成动画.

    • F会由Foo & Bar状态中的ObjectAnimation来引发动画.他不会被VSM去生成程序化的动画.因此,属性F会简单的根据Bar的值来发生动画

返回到WeatherControl,我们同样加了明确的过渡效果为以下几个状态Sunny->PartlyCloudy, Sunny->Cloudy, and PartlyCloudy->Cloudy.

运行一下看看程序的完成效果!你可以从这里下载源码.

下一次

这就是我们学到的关于自定义控件中如何使用VSM,希望你能获得自定义详细过渡效果的乐趣.

下一次,在这系列教程的最后一篇,我们会给出一些使用"部件"与"状态"模式的推荐方式,你还会了解更我关于此模式在未来Silverlight及WPF中的规划

June 25th, 2008 at 8:12 am by . 0 Comments
filed under Silverlight

简化Animation语法

如果你不想在new一个DoubleAnimation()后,做大量的From,To,Duration的操作的话,可以试试C#所支持的简写对象的方式,而且在VS的智能感知中就能原生的支持

简写前

DoubleAnimation opacityAnimation = new DoubleAnimation()opacityAnimation.From = 0;opacityAnimation.To = 1;opacityAnimation.Duration = duration;

简写后

DoubleAnimation opacityAnimation = new DoubleAnimation() { From = 0, To = 1, Duration = duration};

June 25th, 2008 at 8:11 am by . 0 Comments
filed under Silverlight

真正的Loaded事件

做了一些Silverlight开发应该知道,在Loaded事件之后的那个handler之中,画面并没有实际的被layout出来,在Loaded的时候是获得不了ActualWidth或其它相关值的,而只有在Layoutupdated事件中才能获得,但Layoutupdated事件是经常会运行,容易消耗资源,因此有必要找到一个方法,在画面正确渲染出来后,也就是被layouted时,来进行一些操作,之前在WPF中采用过这样一个方法,在这几天也在想办法在Silverlight找寻类似的方法,结论代码如下:

//构造中加Loaded事件Loaded+=new RoutedEventHandler(Page_Loaded);//Loaded Event handlervoid Page_Loaded(object sender, RoutedEventArgs e){Debug.WriteLine("Loaded Event:"+this.ActualWidth);Thread thread = new Thread(new ThreadStart(() =>{this.Dispatcher.BeginInvoke(new Action(() =>{Debug.WriteLine("Thread Start After Loaded Event:" + ActualWidth);}));}));thread.Start();       }

输出结果:

Loaded Event:0Thread Start After Loaded Event:400

在我的项目中已经能很准确的获得ActualWidth,未经更复杂的layout情况下的证实,但我想应该是目前我能用到的唯一的解决方案,在构造中调用线程也是一样的效果,简单写一下,可以像有一个UILoaded事件一样:

public partial class Page : UserControl{public Page(){InitializeComponent();(new Thread(new ThreadStart(() => { Dispatcher.BeginInvoke(UILoaded); }))).Start();}void UILoaded(){Debug.WriteLine("UILoaded:" + ActualWidth);}}

June 25th, 2008 at 8:10 am by . 0 Comments
filed under Silverlight

Silverlight Beta1 to Beta2的几个碰见的情况

1,使用WebClient
引入System.NET.dll (以前不需要)

2,要使用Linq
引入System.Xml.Linq.dll (以前不需要)

3,DP后面要有new PropertyMetadata(new PropertyChangedCallback(CategoryDataCallBack))

4,Resource.Add(value)变成了Resource.Add(key,value);必须设key

5,Storyboard.SetTargetProperty(LeftAnimation,"(Canvas.Left)");
Storyboard.SetTargetProperty(LeftAnimation, new PropertyPath("(Canvas.Left)"));

June 20th, 2008 at 8:16 am by . 0 Comments
filed under Silverlight

[翻译]Part&States Model With VisualStateManager(1/4)

一篇好文章,简单翻译出来与大家共享

VisualStateManager视觉管理器下的"Part(部件)与States(状态)"模式 原文地址

在Silverlight 2 Beta 2中,我们为管理控件中的状态和过渡效果增加了重要的支持.为了帮助理解Parts & States Model("部件与状态"模式),我会为此写一个4篇的系列文章去显示如何做到以下几点:

  • 使用"部件与状态"模式来创建控件的约定
  • 连接控件的逻辑到"部件与状态"
  • 使用状态和部件来设计控件模板

VisualStateManager(视觉状态管理器)是这一切得以实现的原因所在,我们喜欢简称为VSM,VSM可以使用在UserControl(用户控件)和Custom Control(自定义控件)中.

今天的内容介绍部件与状态模型的概念

(注意:文章假设你已经基本了解用户控件,自定义控件及控件模板,如果你还没了解,可以看看我在Mix08上的有关课程或我在TechED上的课程

Let’s get started!

"部件与状态"模式的产生原因

自定义控件是Silverlight控件中的一种,用于严格分离控件逻辑与控件的视觉呈现.这对于你想在自定义视觉呈现时不影响程序逻辑来说是非常有用的,或修改逻辑时不影响视觉呈现

尽管这种严格的分离有很多好处,但很难让设计师去理解在控件的模板中到底需要什么元素.这主要由于约定不够清晰

如果控件开发者提供了明确的控件约定,设计师就能为控件模板提供相应的素材.这样会使得控件的皮肤化变得容易(而"部件与状态"模式就是一种提供约定的方式)

概念:"部件与状态"模式Parts & States Model

"部件与状态"模式是提供控件接口约定的一种方法

这是一种推荐的实现Silverlight 2 控件结构的方法.但这个方式在实际工作时不是强制的,你可以选择直接开发控件而不使用这种方式

由上所述,不但我们认为部件与状态模型是一个好的模式-Expression Blend也会支持这个模式(在IDE下直接可视化修改你的自定义控件的外观).因此,如
果你想让你的控件在Blend中被很好的支持(Skinnable可换肤),你应该使用"部件与状态"模式

深层次说,对于"部件与状态"模式有四个概念

  • 部件Parts
  • 状态States
  • 过度效果(状态之间的)Transitions
  • 状态组State Groups

部件Parts

部件是控件模板中的被命名元素.控件的程序逻辑期望控件在模板中被定义(一种约定,定好名称,程序逻辑会按定好的名称去找这个控件,并操作他),因为程序逻辑会操作这些部件

在上面的Slider滑条例子中,有四个部件,每一个都都能被控件的代码访问到.当UpRepeatButton被按下,控件代码会控制Thumb在Track的范围内向右移动.当DownRepeatButton被按下,就相反.(程序逻辑之所以能完成这些操作,是因为这些控件的名称被约定好了,我们只要遵守名称,放相应的对象在上面,并按这个名称命名,程序逻辑就知道这个部件是做什么用的,并操作他完成相应的功能)

状态States

视觉状态(Visual states)为不同的逻辑状态(logical state)提供提供不同的控件显示.


For instance, the Button above has a light background when in the MouseOver state, and a

例如,在MouseOver状态,按钮显示高亮的背景色,在按下时显示一个较暗的背景.

过渡效果Transitions

视觉过渡效果为控件几个视觉状态间转换提供一种过度的动画效果

如上,按钮背景从亮色变向淡色当由MouseOver转向Pressed状态时.(实际上中间有一个颜色过渡动画过程,并不是直接切到下一个状态的)

状态组StateGroups

一个状态组由多个状态组成.可以有多个状态组,可在一个状态下你可以使用二个状态组下的不同的二个状态

如上的CheckBox例子,有二个状态组:CommonStates和CheckStates.CheckBox可以同时有MouseOver和Indeterminate状态因为这二个状态分属不同的状态组.另一方面,CheckBox不可能同时有Normal和MouseOver状态因为这二个在同一个状态组.

状态组是一个在Beta2中提出的新概念.帮助我们解决在Beta1中出现的状态过多的问题.CheckBox在Beta2中有7个状态(加上二个focus焦点状态).在Beta1中,则有12个状态(focus是部件而非状态).

开始状态改变

当控件检测到逻辑上的状态改变时,会让他的视觉状态改变,引发视觉过渡动画效果来显示相应的视觉状态

在上面的例子中,一个控件检测到MouseEnter事件.就引发视觉状态改变.控件的呈现会调用相应的过度效果然后再停止到MouseOver视觉状态

下篇内容

了解了部件和状态模式的概念,在下一部分,我们开始了解如何基于部件和状态模式来给CheckBox换肤

June 20th, 2008 at 8:15 am by . 0 Comments
filed under Silverlight

[翻译]Part&States Model With VisualStateManager(2/4)

原文地址

这是四篇关于介绍Silverlight 2 控件的"部件"与"状态"系列中的第二篇.

今天,我们将概念进行实践,实现上次所说的CheckBox的换肤(如果你还没读过上一篇,请先读第一篇).

注意:为了方便阅读我尽可能减短XAML标签.你可以从这里下载完整的代码

CheckBox的控件模板(ControlTemplate)

控件模板定义自定义控件的视觉呈现.CheckBox的控件模板代码我们下面有贴出来.

视觉效果:

XAML:

      

在上面的控件模板中,你可能发现了有不少元素透明度Opacity为0.因为在控件的最基本的状态中,这些元素是不可见的.然而,在控件模板中并没有实现视觉上的交互,但当你点击CheckBox时,这些元素仍不可见.

我们来解决这个问题!

增加 VisualStates(视觉状态) & VisualStateGroups(视觉状态组)

基于上次的讨论,在"部件"与"状态"模式中我们引入了视觉状态和视觉状态组的概念.

在Silverlight 2,我们希望这些主意能成为基本的类的概念让用户使用时能把这些概念引入他们自己的类中,所以我们建立了VisualState和VisualStateGroup类,并由VisualStateManager来管理.

我们看看如何将VisualStates & VisualStateGroups加到我们自己的CheckBox皮肤中!

增加VisualStateGroups到CheckBox的控件模板(ContrlolTemplate)

CheckBox有二个主要的状态组(其实有3个,但为了简单示例,我们先忽略focsu这个组)

  • CommonStates state group
  • CheckStates state group

你可以把这些状态组加入控件模板中像下面这样:


如XAML所示,使用状态组你需要做如下声明…

  • 使用vsm的xmlns前缀

    • This is required in Silverlight 2 Beta 2 because of known bug.
      这是一个已知bug我们必须使用vsm的声明
    • xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"

  • 增加VisualStateManager.VisualStateManager属性

    • This attached dependency property should be on the ControlTemplate’s root visual.
      这是一个依赖属性应该在控件模板的root visual根视觉上.
    • 然后在下面定义另一个不同的状态组
  • 包含适当的状态组

    • 每个状态组是命名的并包含多个独立的状态.

现在我们增加了VisualStateGroups,下一步是启用他们.

增加状态VisualStates到状态组VisualStateGroup

CheckBox在二个状态组下共需要七个状态.下图中的蓝色是默认的状态皮肤外观

让我们开始加四个状态到我们的CommonStates中

Storyboard.TargetName="Glow"Storyboard.TargetProperty="Opacity"Duration="0" To="1"/>Storyboard.TargetName="InnerBorder"Storyboard.TargetProperty="(Border.BorderBrush).(GradientBrush.GradientStops)[0].(GradientStop.Color)"Duration="0" To="#FF000000"/>Storyboard.TargetName="InnerBorder"Storyboard.TargetProperty="(Border.BorderBrush).(GradientBrush.GradientStops)[1].(GradientStop.Color)"Duration="0" To="#FF000000"/>我们来看看上面的VisualState元素...
  • 被命名的
    • 被命名,使得VisualStateManager可以在模板中找得到你的状态
  • 包含故事板
    • 故事板用于让状态改变时如何呈现视觉
    • 可以是一个"静态"故事板,意味着可以是0时长的故事板让状态变化时直接变化而不需要动画
    • 也可以是steady state animation持续不停的故事板.换句话说,一个非0时长的故事板有永远循环的行为.使得像是一个不停的动画循环效果.
如果你看了这些我们加入的特别的状态后:
  • Normal状态不包含故事板,因为Normal状态和控件的基础状态一样.
  • MouseOver状态变化Glow元素的透明度,让鼠标移上时有些发光效果.
  • Pressed状态变化CheckBox边框的颜色,也调整高光边框的透明度.
  • Disable状态让整个控件变灰.
为了清晰一些,我们看下面的一个有关各状态的截屏:下面再看看CheckStates:
Storyboard.TargetName="Checkmark"Storyboard.TargetProperty="Opacity"Duration="0" To="1"/>Storyboard.TargetName="IndeterminateRect"Storyboard.TargetProperty="Opacity"Duration="0" To="1"/>

我们为CheckStates状态组加了三个视觉状态:

  • UnCheck状态,和Normal状态一样,没有定义故事板,和控件基础状态一样.

  • Checked状态调整CheckMark图形的透明度.

  • Indeterminate状态调整Indeterminate矩形的透明度.

下面是Check States的截屏:

Sweet!

我们创建了所有的视觉状态,接下来做什么呢?

现在,控件的代码使用VisualStateManager来管理各状态的变化.(下次你会学到控件代码到底在做什么)在控件模板中,你不需要为状态做任何检测或使用的操作.

来看看最新的换肤的CheckBox,演示点击这里.

增加视觉过渡VisualTransitions

如果你看了刚才的应用程序示例,你可能注意到各状态间的显示很突然,让整个用户体验很沉闷生硬.如何让各状态间的变化有过渡呢?在Silverlight,你需要在状态组中加入一些视觉过渡VisualTransitions.

为一个状态组中加入一个默认的视觉过渡

我们想让所有的CommonStates中的状态变化有0.5秒的过渡而在CheckStates中有0.2秒的过渡效果.你可以在各组中加入一个默认的VisualTransition视觉过渡.

在上面的XAML中,你创建了一个默认的VisualTransition并加到了VisualStateGroups.Transitions属性中,来看一下...
  • 有一个Duration属性
    • 这个告诉VisualStateManager你的过渡效果要持续多长时间
VisualStateManger依次会执行并创建过渡动画:这说明了些什么,我们看看一个例子.在Normal 到MouseOver间发生了什么?VisualStateManger检测到了MouseOver状态的故事板对Glow元素的透明度发生了动作,但Normal状态下却没有.他会自动为Glow元素建立0-1的动画.其中0是在Normal状态下定义的值,而1是MouseOver状态下定义的值.VisualStateManger在状态之间做如下事情:检查在二个状态间的属性并在二个值之间创建合适的过渡效果.结果是控件看起来状态切换得很平换而不需要写太多的XAML.可以再看看现在的运行示例.为特别的状态变化创建VisualTransitions一个默认的VisualTransition已经使CheckBox改变很多.但是这样的过渡在某些状态变化中看来还是有些笨拙.例如,你想在MouseOver到Pressed的时候,让视觉突然变化,而不是缓慢过渡.这会使Click的感觉显得更即时一些.你可以按下面的这个方法来指定From和To属性:
你看到,VisualTransition同样有...
  • From 和 To 属性.
    • 这些属性可以使用状态的名称
    • 帮助VSM根据不同的二个状态变化来选择合适的过渡方式
通过检查这些属性,VisualStateManager为当前状态改变选择最明确的过渡方式.当我们的CheckBox从MouseOver到Pressed时发生了什么?VisualStateManager找第一个From="MouseOver"/To="Pressed"的过渡,如果不存在,VSM就搜索单一个 To="Pressed"的过渡,然后如果必要,找找一个From="MouseOver"的过渡.最后.如果都没找到,就用默认的过渡来完成这个状态过渡.如果没有默认的过渡,就会使用0时长的过渡,也就会立刻跳到下一个状态.通过给了更多的设定,我们的CheckBox现在看起来非常好!运行最终的程序点这里,你可以获得完整的XAML代码及完整的程序代码下一篇我们了解了VisualStagemanager的基本使用.下一次,你会看如何从0开始搭建自定义的控件并使用"部件"及"状态"模式.你还会学到如何在模板中使用部件并做更复杂的过渡效果

June 20th, 2008 at 8:15 am by . 0 Comments
filed under Silverlight

Silverlight中的Mask动画

之前也有很多人问我,我当时也不敢肯定,觉得应该是没有,但结果是, Silverlight中的确支持对Clip的值进行动画,如图:

方法是这样,给对象建立Clip后,在故事板中,可以右键单击这个对象,Release Clip,把Clip对象分离出来, 然后在时间线上给Clip做动画,再在时间线上把Clip对象与原对象组合为带Clip的对象,Over!

需要补充的是,针对Clip Path的动画只能是针对Clip中的各节点进行控制,如果你对一个Path执行RendTranform中的各种变化,那么再把Clip组合回对象的话,就无法记录动画,如果想做位移,就只能调整各节点,或选择所有节点,进行一个运动..使Blend为这个Clip形成一些Segment Path方面的动画

June 20th, 2008 at 8:14 am by . 0 Comments
filed under Silverlight

Silverlight 2 beta 2 Release Soon

Silverlight 2 Beta 2 即将到来,而除了Beta 2的到来外,另外值得关注的是有关Expression Blend针对Beta 2的更新

其中之一是,新的Expression Blend 2.5 (June 2008),将支持其于IDE情况下的模板建立和修改,也就是还原了与WPF中的Edit Template一样的功能,这样我们在开发Silverlight应用的时候,不用手写大片大片的Xaml代码了

另一则是同样是新的Blend中,将添加对"状态管理器"VisualStateManager的支持,VisualStateManager用于管理控件的状态,这是Silverlight 2 控件中所设定的机制,如按钮有鼠标移上,移开,点击等各种状态,在Silverlight中,所有控件都通过一个叫VisualStateManager的模式进行状态的管理,而在新的Blend中,在IDE中将直接支持对于状态的管理,将大大简化操作,直接在IDE中完成对各状态的视觉效果设计

June 5th, 2008 at 8:18 am by . 0 Comments
filed under Silverlight

Silverlight 2 Beta 1 数据绑定+值转换

Delay s Blog上有一篇文章来了解WPF与Silvrlight中的有关IValueConvert的使用,但看完后发现这又是有关数据绑定的一个又一个很好的例子,有兴趣可以通过他们的代码了解,在这里做一下有关Silverlight中代码的解释

先来看看此应用的主界面XAML

xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PropertyViewerDemonstration;assembly=PropertyViewerSilverlight">



void ListBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Set the parent s DataContext to the ListBox s selected item
var listBox = sender as ListBox;
(listBox.Parent as Panel).DataContext = listBox.SelectedItem;
}
//当用户点击ListBox中的每一项时,将当前页面的数据关联DataContext指向当前选择的这一个单个对象,而当页面的DataContext存在时,页面中其它元素如果有指定数据绑定,那么都将继承DataContext中的数据内容来呈现




void ListBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Set the parent s DataContext to the ListBox s selected item
var listBox = sender as ListBox;
(listBox.Parent as Panel).DataContext = listBox.SelectedItem;
}
//当用户点击ListBox中的每一项时,将当前页面的数据关联DataContext指向当前选择的这一个单个对象,而当页面的DataContext存在时,页面中其它元素如果有指定数据绑定,那么都将继承DataContext中的数据内容来呈现



再来看看这个具体的PropertyViewer.cs

public class PropertyViewer : IValueConverter
//实现了IValueConverter接口,这样才能在数据绑定时设定为转换器
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
...
}
//Convert方法中具体实现了当传进值时,如何转换,并Return返回给数据绑定的位置,具体代码不贴了,大体意思是,如果没有任何参数,返回一个完整的PropertyDetails对象和其下的所有属性值,而如果有参数的话,那么按参数名称返回PropertyDetails对象,而且只返回参数中指定的属性,不返回其它不需要的属性值

May 22nd, 2008 at 8:53 am by . 0 Comments
filed under Silverlight

Silverlight 2 Beta 1 跨域调试 Tips

Thor发现一个Silverlight小贴士,由于跨域问题,如果对方指定了www.a.com能获得数据的话,XAP文件必须放在a.com上才能运行,但是这样无法用VS的IDE调试,但是如果你在本地随便用VS运行一个项目,用VS打开的浏览器,打开www.a.com下的xap文件运行的话,那么由于这个浏览器被IE托管着,所以所有的调试信息都将存在,包括分步执行,非常好用

May 19th, 2008 at 8:52 am by . 0 Comments
filed under Silverlight