【WPF】用CustomControl打造WPF版的Marquee

來源:互聯網
上載者:User

控制項代碼已經更新,支援上下左右四個方向。VS2010工程

/Files/RMay/WPF_Marquee/WpfMarquee.zip

我們知道在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來實現的。

部分代碼如下:

 

Code
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;
                    }
                }
            }
        }

 

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

使用的時候非常簡單

Code
            <!--文字可以-->
            <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方法中重新啟動。

源碼下載:

/Files/RMay/WPF_Marquee/WpfMarquee.rar

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.