[Silverlight入门系列]使用MVVM模式(9): 想在ViewModel中控制Storyboard动画?

简介: 原文 http://www.cnblogs.com/Mainz/archive/2011/08/25/2153828.html在前面的Silverlight入门系列文章中穿插讲了一些MVVM模式系列文章,MVVM模式貌似简单,其实要把界面逻辑抽象出来还是很不容易,像《TreeView真正实现MVVM模式和Expanded发生时异步动态加载子节点(WCFRiaService)》就不是这么简单,有的童鞋像feiyang还要实现Treeview的展开状态持久化和自动恢复,配合MVVM实现不容易。

原文 http://www.cnblogs.com/Mainz/archive/2011/08/25/2153828.html

前面Silverlight入门系列文章中穿插讲了一些MVVM模式系列文章,MVVM模式貌似简单,其实要把界面逻辑抽象出来还是很不容易,像《TreeView真正实现MVVM模式和Expanded发生时异步动态加载子节点(WCFRiaService)》就不是这么简单,有的童鞋像feiyang还要实现Treeview的展开状态持久化和自动恢复,配合MVVM实现不容易。所以,MVVM的核心概念理解不难,在具体使用上则问题多多。今天要讲的话题就是一个MVVM使用上的具体问题: Silverlight中的Storyboard动画是否可以在ViewModel中来控制?

 

为什么想在ViewModel中控制Storyboard?

假设我的业务逻辑在ViewModel中,业务操作好了保存Save成功了就需要启动一个动画:Stobyboard.begin()。而这个动画 在视图中,怎么去控制它?这个需求很普遍吧。确实很普遍,但实现就不那么简单了,不像下面这样的Storyboard启动那么简单:

   1: <Image x:Name="myImage" 
   2:   Source="http://www.silverlightinaction.com/man.png">
   3:   <Image.Triggers>
   4:     <EventTrigger RoutedEvent="Image.Loaded">
   5:       <BeginStoryboard> 
   6:         <Storyboard x:Name="myStoryboard"> 
   7:           <DoubleAnimation Duration="0:0:2"
   8:                            Storyboard.TargetName="myImage"
   9:                            Storyboard.TargetProperty="Opacity"
  10:                            From="0" To="1" />
  11:         </Storyboard>
  12:       </BeginStoryboard>
  13:     </EventTrigger>
  14:   </Image.Triggers>
  15: </Image>

 

解决方法一:ViewModel中用事件Event通知View启动Storyboard动画

ViewModel是对界面逻辑、业务逻辑、和模型数据的封装和抽象,ViewModel不依赖于具体的View视图,所以ViewModel根本 不知道具体的某个Storyboard,怎么去启动这个动画呢? 解决问题思路有好多:第一种方法就是很自然的想到在ViewModel中用事件Event通知View启动动画。具体做法是:在ViewModel中添加 一个事件Event,当业务操作好了保存Save成功了用这个事件通知View,这样View在Event的处理函数里面打开动画即可。

ViewModel代码:

   1: public class YourViewModel 
   2: { 
   3:     public delegate void YourEventHandler(object sender, EventArgs e); 
   4:     public event YourEventHandler YourEvent; 
   5:     protected void OnYourEvent(EventArgs e) { 
   6:         if (YourEvent != null) YourEvent(this, e); 
   7:     } 
   8:     
   9:     //当业务操作好了保存Save成功了触发这个事件
  10:     //OnYourEvent(new EventArgs(a));
  11: } 

在Xaml.cs写code behind代码:

   1: var vm = new YourViewModel();
   2: vm.YourEvent += (s,e) => 
   3: {
   4:    var story = Resources["YourTransition"] as Storyboard;
   5:    story.Begin();
   6: }; 
   7: this.DataContext = vm;

 

解决方法二:ViewModel属性和View绑定并用Trigger

大家知道,ViewModel的属性可以和View绑定,当属性变化的时候用NotifyPropertyChanged自动通知View。按照这 个思路,我们只要在ViewModel加一个属性,当业务操作好了保存Save成功了就改变这个属性的值,然后就会自动通知View,在View中加个 Trigger,当绑定的值变化的时候就触发启动动画。

假设ViewModel属性为bool PopupSideShow. 在视图中:

   1: xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 

Storyboard定义在Resource中:(此处Storyboard没实际意义仅为演示)

   1: <UserControl.Resources>
   2:     <Storyboard x:Name="popupSideShowStory">
   3:         <DoubleAnimation Storyboard.TargetName="PopUpDisplaySide" Storyboard.TargetProperty="Height" From="0" To="{Binding _PopupSideHeight}" Duration="0:0:1" />
   4:         <DoubleAnimation Storyboard.TargetName="PopUpDisplaySide" Storyboard.TargetProperty="Width" From="0" To="{Binding _PopupSideWidth}" Duration="0:0:1" />
   5:     </Storyboard>
   6:     <Storyboard x:Name="popupSideHideStory">
   7:         <DoubleAnimation Storyboard.TargetName="PopUpDisplaySide" Storyboard.TargetProperty="Height" From="{Binding _PopupSideHeight}" To="0" Duration="0:0:.8" />
   8:         <DoubleAnimation Storyboard.TargetName="PopUpDisplaySide" Storyboard.TargetProperty="Width" From="{Binding _PopupSideWidth}" To="0" Duration="0:0:.8" />
   9:     </Storyboard>
  10: </UserControl.Resources>

在View视图中绑定ViewModel属性为bool PopupSideShow,并用Trigger实现当绑定的值PopupSideShow变化的时候就触发启动动画:

   1: <Grid x:Name="PopUpDisplaySide"  Background="White">
   2:    <i:Interaction.Triggers>
   3:       <ei:DataTrigger Binding="{Binding PopupSideShow}" Value="true">
   4:          <ei:ControlStoryboardAction Storyboard="{StaticResource popupSideShowStory}"/>
   5:       </ei:DataTrigger>
   6:       <ei:DataTrigger Binding="{Binding PopupSideShow}" Value="false">
   7:          <ei:ControlStoryboardAction Storyboard="{StaticResource popupSideHideStory}"/>
   8:       </ei:DataTrigger>
   9:    </i:Interaction.Triggers>
  10:    <StackPanel Orientation="Vertical">
  11:       <TextBlock Text="{Binding _PopupTitle}" FontSize="16" />
  12:    </StackPanel>
  13: </Grid>

 

解决方法三:加一个中间人管理Storyboard从而既实现ViewModel和View解耦,又能在ViewModel控制StoryboardViewModel属性和View

既然我们想在ViewModel里面控制Storyboard,而ViewModel又不能依赖具体的View,所以我们可以加个中间人把 Storyboard抽象出来,这样既能实现ViewModel和View解耦,又能在ViewModel通过中间人控制Storyboard。这个思路 我想也是很自然的。但怎么实现呢?首先这个中间人要和View发生联系必须要能在Xaml里面绑定,所以我们要实现 DependencyProperty。

我们首先加一个StoryboardManager:

   1: using System;
   2: using System.Windows;
   3: using System.Windows.Media.Animation;
   4: using System.Collections.Generic;
   5:  
   6: namespace TestVMAnimation
   7: {
   8:     public class StoryboardManager
   9:     {
  10:         public static DependencyProperty IDProperty =
  11:             DependencyProperty.RegisterAttached("ID", typeof(string), typeof(StoryboardManager),
  12:                     new PropertyMetadata(null, IdChanged));
  13:         
  14:         static readonly Dictionary<string, Storyboard> Storyboards = new Dictionary<string, Storyboard>();
  15:  
  16:         public delegate void Callback(object state);
  17:  
  18:         /// <summary>
  19:         /// IDs the changed.
  20:         /// </summary>
  21:         /// <param name="obj">The obj.</param>
  22:         /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
  23:         private static void IdChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
  24:         { 
  25:             var sb = obj as Storyboard; 
  26:             if (sb == null)            
  27:                 return; 
  28:             
  29:             var key = e.NewValue as string; 
  30:             if (Storyboards.ContainsKey(key))            
  31:                 Storyboards[key] = sb; 
  32:             else            
  33:                 Storyboards.Add(key, sb); 
  34:         }
  35:  
  36:         /// <summary>
  37:         /// Plays the storyboard.
  38:         /// </summary>
  39:         /// <param name="id">The id.</param>
  40:         /// <param name="callback">The callback.</param>
  41:         /// <param name="state">The state.</param>
  42:         public static void PlayStoryboard(string id, Callback callback, object state) 
  43:         { 
  44:             if (!Storyboards.ContainsKey(id)) 
  45:             { 
  46:                 callback(state); 
  47:                 return; 
  48:             } 
  49:             Storyboard sb = Storyboards[id]; 
  50:             EventHandler handler = null;
  51:             EventHandler handlertemp = handler;
  52:             handler = delegate { sb.Completed -= handlertemp; callback(state); }; 
  53:             sb.Completed += handler; 
  54:             sb.Begin(); 
  55:         }
  56:  
  57:         /// <summary>
  58:         /// Sets the ID.
  59:         /// </summary>
  60:         /// <param name="obj">The obj.</param>
  61:         /// <param name="id">The id.</param>
  62:         public static void SetID(DependencyObject obj, string id) 
  63:         { 
  64:             obj.SetValue(IDProperty, id); 
  65:         }
  66:  
  67:         /// <summary>
  68:         /// Gets the ID.
  69:         /// </summary>
  70:         /// <param name="obj">The obj.</param>
  71:         /// <returns></returns>
  72:         public static string GetID(DependencyObject obj) 
  73:         { 
  74:             return obj.GetValue(IDProperty) as string; 
  75:         }
  76:     }
  77:     
  78: }

有了DependencyProperty就可以在Xaml里面绑定了,注意下面的StoryboardManager.ID:

   1: <UserControl.Resources>
   2:     <Storyboard x:Key="YourStoryboardResourceKey" 
   3:              StoryboardManager:StoryboardManager.ID="YourAnimation">
   4:         <DoubleAnimation By="360" Duration="0:0:1" Storyboard.TargetName="btn1"
   5:                          Storyboard.TargetProperty="Angle" />
   6:     </Storyboard>
   7: </UserControl.Resources>

在ViewModel里面控制Storyboard很简单,下面这个例子是通过Command调用的,你当然也可以不通过Command直接调用 Storyboard,像本文的例子,可以在ViewModel的业务逻辑里面当业务操作好了保存Save成功了启动Storyboard动画。

   1: public class YourViewModel
   2: {
   3:     public ICommand PlayStoryboardCommand   {  get; private set;  }
   4:     
   5:     public YourViewModel()
   6:     {
   7:         PlayStoryboardCommand = new DelegateCommand(
   8:             () => {
   9:                         StoryboardManager.PlayStoryboard("YourAnimation", (o) => { }, null);
  10:         });
  11:     }
  12:  
  13:     
  14: }

 

解决方法四:不要在ViewModel里面控制Storyboard,把Transition封装在控件中

用MVVM模式的出发点之一就是分离关注点(Separation of concerns). View负责什么?UI Layout, structure, appearance,animation, 那View的CodeBehind(Xaml.cs)可以有什么?View的Code Behind可以有Initialize Component, 可以有Xaml里面表示不了的视觉行为,比如复杂动画控制(带callback,completed事件那种)。还可以是视觉元素的控制。总之,只要这些 代码是View该负责的,是高内聚的,是不想被重用的,是不能被测试的,那你就搁在code behind好了。绝对应该避免业务逻辑在里面哦。某位大神说过,“解决问题的最好办法是think different,说不定问题本身就不是个问题”。是的,你想在ViewModel里面控制Storyboard,这本身是不是有问题? 想想我们的动画一般在什么时候发生?真的是业务逻辑完成了发生吗?真的和业务逻辑相关吗?不!动画其实是和VisualElement的 VisualState相关。也就是说,我们往往是在某个panel显示/隐藏/打开/关闭的时候有个淡入淡出、推箱子、跳跃、或者x/y/z/3D旋转 的效果(不要告诉我是显示/隐藏panel本身,这个可以和ViewModel的属性绑定的,不是动画)。说白了就是一个transition,从一个 VisualState到另一个VisualState而已。好了,想清楚了,问题就没有了。也就是说,你无须在ViewModel里面控制 Storyboard,只要在View里面定义好VisualState就可以了,封装在控件行为中,把VisualState动画写在控件的模板中,有 关怎么封装Silverlight控件这儿就不多说了,下回有空再说。具体做法可以参考MSDN这个页面,里面就有button的VisualState切换动画,比如MouseOver等:

   1: <Style TargetType="Button">
   2:       <Setter Property="Background" Value="#FF1F3B53"/>
   3:       <Setter Property="Foreground" Value="#FF000000"/>
   4:       <Setter Property="Padding" Value="3"/>
   5:       <Setter Property="BorderThickness" Value="1"/>
   6:       <Setter Property="BorderBrush">
   7:           <Setter.Value>
   8:               <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
   9:                   <GradientStop Color="#FFA3AEB9" Offset="0"/>
  10:                   <GradientStop Color="#FF8399A9" Offset="0.375"/>
  11:                   <GradientStop Color="#FF718597" Offset="0.375"/>
  12:                   <GradientStop Color="#FF617584" Offset="1"/>
  13:               </LinearGradientBrush>
  14:           </Setter.Value>
  15:       </Setter>
  16:       <Setter Property="Template">
  17:           <Setter.Value>
  18:               <ControlTemplate TargetType="Button">
  19:                   <Grid>
  20:                       <vsm:VisualStateManager.VisualStateGroups>
  21:                           <vsm:VisualStateGroup x:Name="CommonStates">
  22:                               <vsm:VisualState x:Name="Normal"/>
  23:                               <vsm:VisualState x:Name="MouseOver">
  24:                                   <Storyboard>
  25:                                       <DoubleAnimation Duration="0" Storyboard.TargetName="BackgroundAnimation" Storyboard.TargetProperty="Opacity" To="1"/>
  26:                                       <ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" To="#F2FFFFFF"/>
  27:                                       <ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)" To="#CCFFFFFF"/>
  28:                                       <ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[3].(GradientStop.Color)" To="#7FFFFFFF"/>
  29:                                   </Storyboard>
  30:                               </vsm:VisualState>
  31:                               <vsm:VisualState x:Name="Pressed">
  32:                                   <Storyboard>
  33:                                       <ColorAnimation Duration="0" Storyboard.TargetName="Background" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="#FF6DBDD1"/>
  34:                                       <DoubleAnimation Duration="0" Storyboard.TargetName="BackgroundAnimation" Storyboard.TargetProperty="Opacity" To="1"/>
  35:                                       <ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)" To="#D8FFFFFF"/>
  36:                                       <ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" To="#C6FFFFFF"/>
  37:                                       <ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)" To="#8CFFFFFF"/>
  38:                                       <ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[3].(GradientStop.Color)" To="#3FFFFFFF"/>
  39:                                   </Storyboard>
  40:                               </vsm:VisualState>
  41:                               <vsm:VisualState x:Name="Disabled">
  42:                                   <Storyboard>
  43:                                       <DoubleAnimation Duration="0" Storyboard.TargetName="DisabledVisualElement" Storyboard.TargetProperty="Opacity" To=".55"/>
  44:                                   </Storyboard>
  45:                               </vsm:VisualState>
  46:                           </vsm:VisualStateGroup>
  47:                           <vsm:VisualStateGroup x:Name="FocusStates">
  48:                               <vsm:VisualState x:Name="Focused">
  49:                                   <Storyboard>
  50:                                       <DoubleAnimation Duration="0" Storyboard.TargetName="FocusVisualElement" Storyboard.TargetProperty="Opacity" To="1"/>
  51:                                   </Storyboard>
  52:                               </vsm:VisualState>
  53:                               <vsm:VisualState x:Name="Unfocused" />
  54:                           </vsm:VisualStateGroup>
  55:                       </vsm:VisualStateManager.VisualStateGroups>
  56:                       <Border x:Name="Background" CornerRadius="3" Background="White" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}">
  57:                           <Grid Background="{TemplateBinding Background}"  Margin="1">
  58:                               <Border Opacity="0"  x:Name="BackgroundAnimation" Background="#FF448DCA" />
  59:                               <Rectangle x:Name="BackgroundGradient" >
  60:                                   <Rectangle.Fill>
  61:                                       <LinearGradientBrush StartPoint=".7,0" EndPoint=".7,1">
  62:                                           <GradientStop Color="#FFFFFFFF" Offset="0" />
  63:                                           <GradientStop Color="#F9FFFFFF" Offset="0.375" />
  64:                                           <GradientStop Color="#E5FFFFFF" Offset="0.625" />
  65:                                           <GradientStop Color="#C6FFFFFF" Offset="1" />
  66:                                       </LinearGradientBrush>
  67:                                   </Rectangle.Fill>
  68:                               </Rectangle>
  69:                           </Grid>
  70:                       </Border>
  71:                       <ContentPresenter
  72:                               x:Name="contentPresenter"
  73:                               Content="{TemplateBinding Content}"
  74:                               ContentTemplate="{TemplateBinding ContentTemplate}"
  75:                               VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
  76:                               HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
  77:                               Margin="{TemplateBinding Padding}"/>
  78:                       <Rectangle x:Name="DisabledVisualElement" RadiusX="3" RadiusY="3" Fill="#FFFFFFFF" Opacity="0" IsHitTestVisible="false" />
  79:                       <Rectangle x:Name="FocusVisualElement" RadiusX="2" RadiusY="2" Margin="1" Stroke="#FF6DBDD1" StrokeThickness="1" Opacity="0" IsHitTestVisible="false" />
  80:                   </Grid>
  81:               </ControlTemplate>
  82:           </Setter.Value>
  83:       </Setter>
  84:   </Style>

 

解决方法五:把Storyboard作为ViewModel的一个属性给View来绑定(糟糕的主意)

也许有人会想到这个主意:在ViewModel中加个Storyboard类型的属性,给view绑定传进去,这样在ViewModel的业务逻辑 中当业务操作好了保存Save成功了就可以直接调用自己的Storyboard.begin(),岂不爽哉?我想说这是个糟糕的主意,为什么?不要把业务 逻辑无关的纯UI的元素混到viewModel里面,难道要抽象依赖于具体?

 

解决方法六:用VisualStateManager,在ViewModel用事件通知View(仅供参考)

用VisualStateManager的方法(Event同方法一的事件),在视图收到事件通知以后,调用StateManager启动动画而已。在xaml.cs中:

   1:  
   2: VisualStateManager.GoToState(this, "YourState1", true);
   3:  
在Xaml中把动画不要定义在Resource中,而是定义为几个VisualState:
   1: xmlns:ic="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"
   2:  
   3: <Grid x:Name="LayoutRoot">
   4:         <VisualStateManager.CustomVisualStateManager>
   5:             <ic:ExtendedVisualStateManager/>
   6:         </VisualStateManager.CustomVisualStateManager>
   7:         <VisualStateManager.VisualStateGroups>
   8:             <VisualStateGroup x:Name="EditViewGroup" ic:ExtendedVisualStateManager.UseFluidLayout="True">
   9:                 <VisualStateGroup.Transitions>
  10:                     <VisualTransition GeneratedDuration="00:00:00.2500000"/>
  11:                 </VisualStateGroup.Transitions>
  12:                 <VisualState x:Name="YourState1">
  13:                     <Storyboard>
  14:                         <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="GridFlyout" Storyboard.TargetProperty="(FrameworkElement.Margin)">
  15:                             <DiscreteObjectKeyFrame KeyTime="00:00:00">
  16:                                 <DiscreteObjectKeyFrame.Value>
  17:                                     <Thickness>0,0,0,-101</Thickness>
  18:                                 </DiscreteObjectKeyFrame.Value>
  19:                             </DiscreteObjectKeyFrame>
  20:                         </ObjectAnimationUsingKeyFrames>
  21:                     </Storyboard>
  22:                 </VisualState>
  23:                 <VisualState x:Name="YourState2">
  24:                     <Storyboard>
  25:                         <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="GridFlyout" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
  26:                             <EasingDoubleKeyFrame KeyTime="00:00:00" Value="3"/>
  27:                         </DoubleAnimationUsingKeyFrames>
  28:                         <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="GridFlyout" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">
  29:                             <EasingDoubleKeyFrame KeyTime="00:00:00" Value="-101"/>
  30:                         </DoubleAnimationUsingKeyFrames>
  31:                         <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="GridFlyout" Storyboard.TargetProperty="(FrameworkElement.Margin)">
  32:                             <DiscreteObjectKeyFrame KeyTime="00:00:00">
  33:                                 <DiscreteObjectKeyFrame.Value>
  34:                                     <Thickness>-4,0,0,-101</Thickness>
  35:                                 </DiscreteObjectKeyFrame.Value>
  36:                             </DiscreteObjectKeyFrame>
  37:                         </ObjectAnimationUsingKeyFrames>
  38:                     </Storyboard>
  39:                 </VisualState>
  40:             </VisualStateGroup>
  41:         </VisualStateManager.VisualStateGroups>
  42: </Grid>

 

总结

以上几种方法个人觉得第二种最好,第三种次之,第四种也不错但是比较费时间。我们遇到问题不仅仅是思考问题,解决问题,还要发散思维想想多重解决方案并选择最优最简单的方案;如果当初是赶时间,那后续就需要重构来寻求最优解决方案。这种重构是有意义的。就像我在前一篇中如何在Silverlight页面间传递复杂对象,也给出了5种解决方法,选择最优的一种,好的攻城师应当多钻研,多分享,多接受批评和自我批评,这样才能进步的快一些。

 

继续阅读 – Silverlight入门MVVM系列

 

继续阅读 - Silverlight入门系列

 
目录
相关文章
|
容器
Silverlight & Blend动画设计系列二:旋转动画(RotateTransform)
原文:Silverlight & Blend动画设计系列二:旋转动画(RotateTransform)   Silverlight的基础动画包括偏移、旋转、缩放、倾斜和翻转动画,这些基础动画毫无疑问是在Silverlight中使用得最多的动画效果,其使用也是非常简单的。
1012 0
|
容器 数据可视化 内存技术
Silverlight & Blend动画设计系列一:偏移动画(TranslateTransform)
原文:Silverlight & Blend动画设计系列一:偏移动画(TranslateTransform)   用户界面组件、图像元素和多媒体功能可以让我们的界面生动活泼,除此之外,Silverlight还具备动画功能,它可以让应用程序“动起来”。
816 0
Silverlight & Blend动画设计系列四:倾斜动画(SkewTransform)
原文:Silverlight & Blend动画设计系列四:倾斜动画(SkewTransform)   Silverlight中的倾斜变化动画(SkewTransform)能够实现对象元素的水平、垂直方向的倾斜变化动画效果。
839 0
|
容器
Silverlight & Blend动画设计系列五:故事板(StoryBoards)和动画(Animations)
原文:Silverlight & Blend动画设计系列五:故事板(StoryBoards)和动画(Animations)   正如你所看到的,Blend是一个非常强大的节约时间的设计工具,在Blend下能够设计出很多满意的动画作品,或许他具体是怎么实现的,通过什么方式实现的我们还是一无所知。
941 0
Silverlight & Blend动画设计系列七:模糊效果(BlurEffect)与阴影效果(DropShadowEffect)
原文:Silverlight & Blend动画设计系列七:模糊效果(BlurEffect)与阴影效果(DropShadowEffect)   模糊效果(BlurEffect)与阴影效果(DropShadowEffect)是两个非常实用和常用的两个特效,比如在开发相册中,可以对照片的缩略图添加模糊效果,在放大照片的过程中动态改变照片的大小和模糊的透明度来达到一个放大透明的效果。
1085 0
Silverlight & Blend动画设计系列六:动画技巧(Animation Techniques)之对象与路径转化、波感特效
原文:Silverlight & Blend动画设计系列六:动画技巧(Animation Techniques)之对象与路径转化、波感特效   当我们在进行Silverlight & Blend进行动画设计的过程中,可能需要设计出很多效果不一的图形图像出来作为动画的基本组成元素。
1045 0
|
API
Silverlight & Blend动画设计系列十:Silverlight中的坐标系统(Coordinate System)与向量(Vector)运动
原文:Silverlight & Blend动画设计系列十:Silverlight中的坐标系统(Coordinate System)与向量(Vector)运动   如果我们习惯于数学坐标系,那么对于Silverlight中的坐标系可能会有些不习惯。
1260 0
|
UED
Silverlight & Blend动画设计系列九:动画(Animation)与视图状态管理(Visual State Manager)
原文:Silverlight & Blend动画设计系列九:动画(Animation)与视图状态管理(Visual State Manager)   Silverlight中的动画(Animation)与视图状态管理(Visual State Manager) 结合使用是非常常见的,动画用于管理对象在某段事件段内执行的动画动作,视图状态管理则用于控制对象在多个不同的视觉状态之间切换、导航。
794 0
Silverlight & Blend动画设计系列八:拖放(Drag-Drop)操作与拖放行为(DragBehavior)
原文:Silverlight & Blend动画设计系列八:拖放(Drag-Drop)操作与拖放行为(DragBehavior)   在Silverlight中自身并没有提供拖放功能的相关实现,要实现拖放功能得借助其事件支持(MouseLeftButtonDown、MouseLeftButtonUp和MouseMove)来完成,实际应用中我们可以通过行为(Behavior)特性将拖放操作封装为行为,这样可达到代码复用的效果。
1076 0
Silverlight & Blend动画设计系列十三:三角函数(Trigonometry)动画之飘落的雪花(Falling Snow)
原文:Silverlight & Blend动画设计系列十三:三角函数(Trigonometry)动画之飘落的雪花(Falling Snow)   平时我们所看到的雪花(Falling Snow)飘飘的效果实际上也是一个动画,是由许多的动画对象共同完成的一个界面效果。
962 0

热门文章

最新文章