程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 【WPF】用CustomControl打造WPF版的Marquee

【WPF】用CustomControl打造WPF版的Marquee

編輯:關於.NET

我們知道在html中有一個marquee標簽,可以很方便的實現文字滾動的效果,比如如下簡單的聲明:

<marquee loop="3" behavior="scroll">文本信息<marquee>

在WPF裡面,當然,我們可以用Animation和Storyboard來達到同樣的效果,但是感覺總是不那麼好,每次都需要做動畫。而且設置動畫的屬性很麻煩。能不能就像HTML簡單的聲明就行了呢?比如:

<l:Marquee Content="123" Direction="Right" Behavior="Scroll" ScrollAmount="20" ScrollDelay="500"/>

能夠這樣簡單的指定屬性來使用。

下面我們就用開發CustomControl的方式來打造一個Marquee控件。

首先,我們添加一個自定義控件,這個控件繼承自ContentControl,因為它的裡面可以放任何東西,而不僅僅限於文本。

接著,仿造html中的marquee標簽,定義一些必要的屬性。這些屬性都是DependencyProperty。

接下來我們需要寫動畫的邏輯了。有三種方式來寫這個動畫:

1、利用系統的Animation和Storyboard

2、在CompositionTarget的Rendering事件中寫動畫

3、利用DispatcherTimer寫動畫

我們這兒動畫的行為有好幾種,比較復雜,利用系統的動畫方式來寫會很麻煩,並且這兒有一個ScrollDelay屬性來控制延時,在CompositionTarget的Rendering事件中不太好控制,因此,最後我選擇用DispatcherTimer,在它的Tick事件中寫動畫邏輯。

動畫的邏輯主要就是改變Content的位移,需要注意的是,這個位移是通過TranlateTransform來實現的。

部分代碼如下:

protected virtual void OnUpdateContentPosition()
{
if (_contentHost != null)
{
double contentWidth = _contentHost.DesiredSize.Width;
double leftBound = 0.0, rightBound = 0.0;
// Alternate不飛出邊界
if (this.Behavior == MarqueeBehavior.Alternate || this.Behavior == MarqueeBehavior.Slide)
{
leftBound = 0;
rightBound = this.ActualWidth - contentWidth;
}
// Scroll要飛出邊界
else if (this.Behavior == MarqueeBehavior.Scroll)
{
leftBound = -contentWidth;
rightBound = this.ActualWidth;
}
// 循環次數的計數
if (_currentLoop < this.Loop)
{
// 計算位移
// 這裡邏輯比較重復,可以考慮合並
if (_currentDirection == Direction.Left)
{
_contentTranlate.X -= this.ScrollAmount;
// 從右往左到頭了
if (_contentTranlate.X <= leftBound)
{
if (this.Behavior == MarqueeBehavior.Scroll || this.Behavior == MarqueeBehavior.Slide)
{
_contentTranlate.X = rightBound;
}
else if (this.Behavior == MarqueeBehavior.Alternate)
{
_currentDirection = Direction.Right;
}
_currentLoop += _loopCounter;
}
}
else if (_currentDirection == Direction.Right)
{
_contentTranlate.X += this.ScrollAmount;
// 從左往右到頭了
if (_contentTranlate.X >= rightBound)
{
if (this.Behavior == MarqueeBehavior.Scroll || this.Behavior == MarqueeBehavior.Slide)
{
_contentTranlate.X = leftBound;
}
else if (this.Behavior == MarqueeBehavior.Alternate)
{
_currentDirection = Direction.Left;
}
_currentLoop += _loopCounter;
}
}
}// End of Loop
else
{
// 保證動畫結束後可見
if (_contentTranlate.X < 0)
{
_contentTranlate.X = 0;
}
if (_contentTranlate.X > this.ActualWidth - contentWidth)
{
_contentTranlate.X = this.ActualWidth - contentWidth;
}
}
}
}

更詳盡的內容可以直接參看源碼。

使用的時候非常簡單

<!--文字可以-->
<l:Marquee Content="123" Direction="Right" Behavior="Scroll" ScrollAmount="20" ScrollDelay="500"/>
<!--圖形也可以-->
<l:Marquee Direction="Right" Behavior="Slide">
<Rectangle Width="20" Height="20" Fill="Blue"/>
</l:Marquee>
<!--控件也沒有問題-->
<l:Marquee>
<Button Content="Button" Width="50"/>
</l:Marquee>

需要注意的是,如果設定了Loop,當Loop結束的時候,我並沒有停止Timer,這樣在Window Resize之後動畫會重新播放。讀者可以將選擇其Stop掉,而在ResetAnimation方法中重新啟動。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved