【WPF】用CustomControl打造WPF版的Marquee

控件代码已经更新,支持上下左右四个方向。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来实现的。

部分代码如下:

 

ContractedBlock.gif ExpandedBlockStart.gif 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;
                    }
                }
            }
        }

 

更详尽的内容可以直接参看源码。

使用的时候非常简单

ContractedBlock.gif ExpandedBlockStart.gif 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

转载于:https://www.cnblogs.com/RMay/archive/2009/01/20/1379023.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值