經過之前的介紹,相信大家已經對Behavior有了初步的概念,但是對於怎麼寫出一個自己的Behavior,應該還是比較沒Fu吧!?
這篇就來跟大家介紹Behavior程式的結構,順便帶大家來實作一個「能用滑鼠滾輪控制放大縮小倍率的放大鏡Behavior」吧!!
經過之前的介紹,相信大家已經對Behavior有了初步的概念,但是對於怎麼寫出一個自己的Behavior,應該還是比較沒Fu吧!?
這篇就來跟大家介紹Behavior程式的結構,順便帶大家來實作一個「能用滑鼠滾輪控制放大縮小倍率的放大鏡Behavior」吧!!
基本上,當你透過Blend建立一個Behavior的Class之後,它預設的程式內容如下:
public Behavior1()
{
// Insert code required on object creation below this point.
//
// The line of code below sets up the relationship between the command and the function
// to call. Uncomment the below line and add a reference to Microsoft.Expression.Interactions
// if you choose to use the commented out version of MyFunction and MyCommand instead of
// creating your own implementation.
//
// The documentation will provide you with an example of a simple command implementation
// you can use instead of using ActionCommand and referencing the Interactions assembly.
//
//this.MyCommand = new ActionCommand(this.MyFunction);
}
protected override void OnAttached()
{
base.OnAttached();
// Insert code that you would want run when the Behavior is attached to an object.
}
protected override void OnDetaching()
{
base.OnDetaching();
// Insert code that you would want run when the Behavior is removed from an object.
}
/*
public ICommand MyCommand
{
get;
private set;
}
private void MyFunction()
{
// Insert code that defines what the behavior will do when invoked.
}
*/
從class的宣告行,我們可以看出Behavior是繼承了System.Windows.Interactivity中的Behavior<DependencyObject>的類別,我們可以透過修改< DependencyObject >來的方式來設定該Behavior能寄生(講附身好像比較貼切)的型別(必需是衍生自DependencyObject的類別),例如修改成Behavior<Button>則代表該Behavior只能附身在Button的 身上,而被附身的物件實體,則可以透過名為AssociatedObject的Property來存取。
除此之外,Behavior必需override兩個重要的Method,第一個是OnAttached,我們得透過這個Method定義出當目標物件被附身之後,它必需處理的事件有哪些;另一個是OnDetaching,一看就知道和OnAttached相反,這邊定義的是當附身解除之後,要善後的動作。
除了上述兩個Method之外,剩下的就是自由發揮創意的時間了,我們可以定義額外的Method,來處理OnAttached中事件觸發的EventListener,或是實作ICommand,以供MVVM中EvnetListener的Binding。
直接以前面提到的放大鏡為例:
public class MagnifierBehavior : Behavior<FrameworkElement>
{
private MagnifyEffect _magnifyEffect;
public MagnifierBehavior() :
base()
{
this._magnifyEffect = new MagnifyEffect();
}
public double Amount
{
get
{
return _magnifyEffect.Amount;
}
set
{
_magnifyEffect.Amount = value;
}
}
public double InnerRadius
{
get
{
return _magnifyEffect.InnerRadius;
}
set
{
_magnifyEffect.InnerRadius = value;
}
}
public double OuterRadius
{
get
{
return _magnifyEffect.OuterRadius;
}
set
{
_magnifyEffect.OuterRadius = value;
}
}
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.MouseEnter += new MouseEventHandler( AssociatedObject_MouseEnter );
this.AssociatedObject.MouseLeave += new MouseEventHandler( AssociatedObject_MouseLeave );
this.AssociatedObject.MouseWheel += new MouseWheelEventHandler( AssociatedObject_MouseWheel );
}
protected override void OnDetaching()
{
base.OnDetaching();
this.AssociatedObject.MouseEnter -= new MouseEventHandler( AssociatedObject_MouseEnter );
this.AssociatedObject.MouseLeave -= new MouseEventHandler( AssociatedObject_MouseLeave );
this.AssociatedObject.MouseWheel -= new MouseWheelEventHandler( AssociatedObject_MouseWheel );
}
private void AssociatedObject_MouseLeave( object sender , MouseEventArgs e )
{
this.AssociatedObject.MouseMove -= new MouseEventHandler( AssociatedObject_MouseMove );
this.AssociatedObject.Effect = null;
}
private void AssociatedObject_MouseEnter( object sender , MouseEventArgs e )
{
this.AssociatedObject.MouseMove += new MouseEventHandler( AssociatedObject_MouseMove );
this.AssociatedObject.Effect = this._magnifyEffect;
}
void AssociatedObject_MouseWheel( object sender , MouseWheelEventArgs e )
{
if( this._magnifyEffect != null )
{
if( e.Delta > 0 && this.Amount <= 0.9 )
{
this.Amount += 0.1;
}
else if( e.Delta < 0 && this.Amount >= -0.9 )
{
this.Amount -= 0.1;
}
}
}
private void AssociatedObject_MouseMove( object sender , MouseEventArgs e )
{
//設定放大鏡的中心位置
( this.AssociatedObject.Effect as MagnifyEffect ).Center = e.GetPosition( this.AssociatedObject );
//設定放大鏡的中心點為滑鼠的相對位置
Point mousePosition = e.GetPosition( this.AssociatedObject );
mousePosition.X /= this.AssociatedObject.ActualWidth;
mousePosition.Y /= this.AssociatedObject.ActualHeight;
this._magnifyEffect.Center = mousePosition;
//撥放動畫
Storyboard zoomInStoryboard = new Storyboard();
DoubleAnimation zoomAnimation = new DoubleAnimation();
zoomAnimation.To = this._magnifyEffect.Amount;
zoomAnimation.Duration = TimeSpan.FromSeconds( 0.5 );
Storyboard.SetTarget( zoomAnimation , this.AssociatedObject.Effect );
Storyboard.SetTargetProperty( zoomAnimation , new PropertyPath( MagnifyEffect.AmountProperty ) );
//動畫撥放完為停止狀態
zoomAnimation.FillBehavior = FillBehavior.HoldEnd;
zoomInStoryboard.Children.Add( zoomAnimation );
zoomInStoryboard.Begin();
}
}
<navigation:Page
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:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:Ouch_Silverlight_Behaviors="clr-namespace:Ouch.Silverlight.Behaviors;assembly=Ouch.Silverlight.Behaviors" x:Class="Ouch.Silverlight.Behaviors.Demo.Pages.MagnifierBehaviorDemo"
mc:Ignorable="d"
d:DesignWidth="640" d:DesignHeight="480"
Title="MagnifierBehaviorDemo Page">
<Grid x:Name="LayoutRoot">
<Image Source="/Ouch.Silverlight.Behaviors.Demo;component/Images/Photo1.jpg">
<i:Interaction.Behaviors>
<Ouch_Silverlight_Behaviors:MagnifierBehavior/>
</i:Interaction.Behaviors>
</Image>
</Grid>
</navigation:Page>
因為我希望到時候所有繼承自FrameworkElement的物件都能被放大鏡附身,因此我把Behavior<T>設為Behavior<FrameworkElement>,而Blend中也內建了一個放大鏡的PixelShaderEffect(這個之後會再找機會向大家介紹),我就直接拿它來用。而我希望當物件被附身之後,可以透過滑鼠移動來改變放大鏡的位置,並且可以透過滑鼠滾輪來改變放大的倍率,因此我在OnAttached Method中設定了兩個EventListener,程式碼有點長,但是其實並不複雜吧!?就這樣,我就做完一個擁有放大鏡效果的Behavior囉!!
最後來看看實作出來的效果吧!!(若想體驗透過滾輪控制縮放程度的功能--請點此開啟新視窗)
最後的最後,附上原始碼,請自行取用: