Mooncake Project

by Allan 18. December 2008 22:15

最近的项目,已经有人在网上公开了.我们称之为Mooncake Viewer,主要功能是可以从FLickr或Smugmug帐号抓取用户的照片,在服务器端生成一个适合Silverlight使用的Deepzoom格式文件.而这个项目中包含一个使用Silverlight开发的Viewer,可以让用户嵌入自己的网站或博客与其它人分享.有兴趣的话可以尝试一下:访问地址

 

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Silverlight

path绘图,并缩放时的问题

by Allan 7. November 2008 21:25

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Silverlight

一些帮助检查Silverlight应用CPU占用的提示

by Allan 2. November 2008 10:06

开发比较动态,图形化的应用,总是会出现CPU占用率高的问题,这个问题无论是WPF还是FLASH还是Silverlight中,都会出现,大部分情况也就是一些loop中,不断的进行一些操作造成的.从最近silverlight 2的开发经验中来看,在一直运行的loop中做赋值操作,有一些效率很高,有一些就非常消耗,举例:在loop中,不停的对对象进行Canvas.SetLeft或SetTop,都不会占用CPU资源,而如果在loop中改变了对象的Scale值..或是所有RenderTransform的值,都会相当消耗CPU资源.改变对象的Visibility,也会严重消耗CPU资源.所以,如果CPU占用高,不妨检查这样一些操作,也许可以不用理会SetLeft,但Visibility和Scale值的改变,就值得注意了!

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Silverlight

Mooncake Viewer 1.0 beta Test

by Allan 27. October 2008 04:17
Get Microsoft Silverlight

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Silverlight

Silverlight中的JS异常处理

by Allan 13. October 2008 20:01
一般当Silverlight运行时发生的一些异常,在一般情况下,都会由Silverlight嵌入页面时的JS给捕获到,所以有时候在看Silverlight的时候,会在左下角看见JS错误的提示框或是一些Alert,常见的就是ImageError,一般由图片路径不对图片不存在引起,为了避免运行时发生这种影响体验的情况,最好的办法还是在C#代码中, 对一些异常的事件进行捕捉,如图片载入失败异常,可以对图片加ImageFailed事件侦听进行捕捉,这样就不会发送到页面的javascript端上去了.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Silverlight

DispatcherTimer vs Storyboard

by Allan 27. June 2008 00:51
在Silverlight做逐帧事件可以用DispatcherTimer计时器,或使用一个空的Storyboard,在每次Completed事件中写你的执行代码然后再启动Storyboard,但是哪一种更好呢?这里有一个解释来自Adam Kinney:

The DispatcherTimer is a lower resolution timer than the timer behind the Storyboard class, which causes loss in fidelity. Additionally, the Storyboard execution is more stable across the different supported OSs and Browsers. I ll put together a sample to show the comparision.

不管怎样使用空的Storyboard来做逐帧是一个很好的解决方案,为此我设计了一个用于替代DispatcherTimer的StoryboardTimer类,可以在程序中和使用DispatcherTimer一样使用:

public class StoryboardTimer
{
private TimeSpan interval;
public TimeSpan Interval {
get { return interval; }
set { 
interval = value;
sbTimer.Duration = new Duration(interval);
}
}
public event RoutedEventHandler Tick;
private void RaiseTick()
{
if (Tick != null)
{
Tick(this, new RoutedEventArgs());
}
}
Storyboard sbTimer;
private bool startFlag;
public static int StoryboardTimerCount = 0;
public StoryboardTimer()
{
sbTimer = new Storyboard();
startFlag = false;
sbTimer.Completed += new EventHandler(sbTimer_Completed);
(Application.Current).Resources.Add("sbTimer"+StoryboardTimer.StoryboardTimerCount, sbTimer);
StoryboardTimer.StoryboardTimerCount++;       
}
void sbTimer_Completed(object sender, EventArgs e)
{
RaiseTick();
if (startFlag)
{
sbTimer.Begin();
}
}
public void Start()
{
startFlag = true;
sbTimer.Begin();            
}
public void Stop()
{
startFlag = false;
}
}


使用方法

StoryboardTimer timer= new StoryboardTimer();
timer.Interval = TimeSpan.FromSeconds(frameRate);
timer.Tick += new RoutedEventHandler(timer_Tick);
void timer_Tick(object sender, RoutedEventArgs e)
{
//dosomething
}

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Silverlight

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

by Allan 26. June 2008 20:05
[原文地址]

这是有关"部件与状态"模式系列的最后一篇!

今天,我们讨论一些关于如何使用"部件与状态"模式的使用建议.我们还会看看有关VisualStageManager在未来的Silverlight及WPF中的情况.

系列链接(第一篇,第二篇,第三篇,第四篇)

"部件与状态"模式使用推荐

1.在UserControls用户控件和Custom Control自定义控件中使用"部件与状态"模式

就像我们在第一篇中提到的,"部件与状态"模式只是一个模式.在实际运行中并不是强制的,你可以在创建控件时不采用这种方式.

但是,我们觉得这是一个很好的模式.而且Blend针对自定义控件的的可视化编辑方式只支持这种模式.

虽然我们这一系列一直关注在自定义控件Custom Controls中的VSM,但是你同样可以在用户控件User Control中使用他.

2.自行命名VSM xmlns

因为一个已知的Silverlight 2 Beta 2 Bug,你必须在头部申明VisualStateManager的xmlns.

xmlns:vsm=“clr-namespace:System.Windows;assembly=System.Windows”


3.命名约定

为了控件的一致性,我们推荐使用如下的一些命名约定.



4.CommonStates 和 FocusStates 比较特殊

许多控件都使用了这二个状态组



如果你的控件也有这些状态的特征,为了一致性,我们推荐使用相同的组名和名称

5.能够适应模板中没有Parts & States的情况

有很多原因能说明为什么控件模板中没有给一些部件和状况:设计师可能没有创建等原因.

需要有一些良好的编写习惯去防止由于部件遗失造成的程序崩溃.

注意:VisualStateManager.GoToState()方法已经有这种预防措施,当VisualState没有找到时,会返回false.

6.考虑支持一个"fallback"状态(当状态不存在时,用另一状态替代)

在复杂的控件中,可以提供一个fallback控制当某些状态不存在时提供一种替代方案

if (VisualStateManager.GoToState(this, “FocusContent”, useTransitions) == false)
{
VisualStateManager.GoToState(this, “Focus", useTransitions);
} 


这个处理方式的好处显而易见:当设计师没有提供合适的状态时,控件能够继续进行一些视觉上的正常表现.

但也有一些不好的影响:fallback状态机制并不是完全整合在"部件与状态"模式中,这意味着Blend软件并不能很好的识别出来(在可视化编辑中)

所以,请减少使用fallback状态并只在控件非常复杂时才使用.

同样,如果你认为这种方式对你有用的话,让我们知道!我们乐意接受你的反馈.

7.子类的状态应该添加在新的状态组中(而不是已存在的状态组)

如你所知,每一个状态组是orthogonal(同时使用二个组中的二个状态).这使得子类很容易添加新的状态组.例如,你可以创建一个StackButton从Button继承并添加一个StackState组:



这个可以正常运作因为StackState状态组的状态是完全独立于Button的CommonStates & FocusStates.

然尔,如果你想把一个新的状态加到一个已经存在的状态组中,这个状态组的逻辑就变得混乱.就无法保证在状态发生时找到正确的状态.

我们这个例子简单一些.BasicControl定义了二个状态在CommonStates中:Normal,MouseOver.创新的逻辑是:


  • if(鼠标没有移上来) goto Normal


  • if(鼠标移上来) goto MouseOver




现在,ExtendedControl从BasicControls继承并想加一个Pressed状态,这个逻辑状态的目标可能是:

  • if(鼠标没有移上来) goto Normal


  • if(鼠标移上来而且鼠标按钮没有按下) goto MouseOver


  • if(鼠标按下) goto Pressed



然尔,并没有好的方式让ExtendedControl去添加有关(而且鼠标按钮没有按下)MouseOver状态的检测,因为这个逻辑存在于Button基类中.

这一切都说明:子类通常只能把状态加到新的状态组中.但我们推荐如果是全新的状态(不破坏原有逻辑的),可以加到状态组中.

注意:为在未来解决这些问题我们有不同的方式(有好的也有坏的).我们现在正在提供一个Triggers-Based基于触发的解决方案.如果想了解更多,继续阅读.

展望未来

VSM & Windows Presentation Foundation

Silverlight的"控件与状态"模式改变了WPF存在的很多现有特性(像ControlTemplates,GetTemplateChild() Hellper,etc).



然尔,这些相关的特性如VisualStateManager和相关的类并不存在于WPF中.好消息是我们在下一版的WPF中会包含VisualStageManager!

为了让大家能够把Silverlight 2的控件和皮肤移植到WPF,下一版.NET Framework会支持得更好一些.为帮助我们实现,我们会在下一版的完整WPF发售前,就中提供一个包含VisualStateManager的程序集.现然这个计划还为时尚早,未来会提供时间表的细节.

未来的Silverlight特性

经常有人问在Silverlight控件模型中,Triggers触发器在哪里?

有很多原因使得我们不打算在Silverlight 2 的发布中加入触发器.一个主要的技术挑战是我们的属性系统架构不够达到能支持触发器.这在未来的Silverlight会改变,并会加入触发器的支持.

触发器和VSM之间如何协作呢?我们初步的方案是这样构想的:




提供一个GoToState触发器去调用状态变化.

设计师会有一个选项去使用内置的控件状态(不使用视觉状态变化的逻辑去控制).或者,设计师愿意在XAML中使用所有的触发器和VSM状态变化.也可能设计师能够自行添加新的状态到新状态组或存在的状态组中,而不去考虑控件的代码的情况下.

更多激动的特性会到来!

结束

这就是这四篇的有关Silverlight 2 "部件与状态"模式的全部了.如果你有问题,请反馈给我们.

如果这一系列还不够了解VisualStateManager,这有一些其它资源:














Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Silverlight

真正的Loaded事件

by Allan 25. June 2008 22:47
做了一些Silverlight开发应该知道,在Loaded事件之后的那个handler之中,画面并没有实际的被layout出来,在Loaded的时候是获得不了ActualWidth或其它相关值的,而只有在Layoutupdated事件中才能获得,但Layoutupdated事件是经常会运行,容易消耗资源,因此有必要找到一个方法,在画面正确渲染出来后,也就是被layouted时,来进行一些操作,之前在WPF中采用过这样一个方法,在这几天也在想办法在Silverlight找寻类似的方法,结论代码如下:
//构造中加Loaded事件
Loaded+=new RoutedEventHandler(Page_Loaded);
//Loaded Event handler
void 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:0
Thread 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);
}
}

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Silverlight

简化Animation语法

by Allan 25. June 2008 22:02
如果你不想在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};

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Silverlight

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

by Allan 25. June 2008 03:06
[原文地址]
这是系列教程的第三篇.

上一次,你学会了如何对现有的控件使用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 DP
public 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中的规划

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Silverlight

Powered by BlogEngine.NET 1.4.5.0
Theme by Mads Kristensen

TextBox

Tag cloud

    RecentPosts