走马灯图片轮播控件----------WinForm控件开发系列

控件的播放原理在动画播放前计算好要播放特图片的信息。动画过程是利用定时器更新图片的信息。

控件播放界面显示的图片可以是一张或多张,每次移动只有一张滑动方的方向一共有四种。

有些人会看到 Images属性的类型是自定义DisplayImageCollection ,而DisplayImageCollection 是继承 IList, ICollection, IEnumerable的,就会觉得为什么这里不用List类型集合。这是有原因的,这是为了能让控件在VS IDE设计窗口使用。我们必须要按照.NET IDE控件开发模式来开发。如果你不按照.NET IDE控件开发模式来开发,你的控件在设计器窗口会报很多错的。如果这个控件只是用纯代码的方式去调用的话你用List类型集合去开发是没有错的。下面以Images属性为例子:

首先你要知道利用VS IDE设计器开发时有很多代码都是由VS IDE设计器自动生成的,假如Images属性是用List类型,那你在Images.Add()后VS IDE设计器是无法立即更新界面。因为Add方法里面没有要处理你的控件的一些逻辑代码。但利用DisplayImageCollection就不一样了,因为DisplayImageCollection是继承 IList, ICollection, IEnumerable,你可以在Add方法里面编写你需要的逻辑。

还有一方面就是在VS IDE设计器模式下你操作Images属性时如果ImagesList集合类型的话是会报错的。

  /// <summary>
  /// 走马灯图片轮播控件
  /// </summary>
  [ToolboxItem(true)]
  [DefaultProperty("Images")]
  [Description("走马灯图片轮播控件")]
  public partial class ImageCarouselExt : Control
  {

    #region

    private bool barShow = true;
    /// <summary>
    ///是否显示导航栏 
    /// </summary>
    [DefaultValue(true)]
    [Description("是否显示导航栏")]
    public bool BarShow
    {
      get { return this.barShow; }
      set
      {
        if (this.barShow == value)
          return;
        this.barShow = value;
        this.Invalidate();
      }
    }

    private Color barNormalColor = Color.Gray;
    /// <summary>
    ///导航栏正常颜色 
    /// </summary>
    [DefaultValue(typeof(Color), "Gray")]
    [Description("导航栏正常颜色")]
    public Color BarNormalColor
    {
      get { return this.barNormalColor; }
      set
      {
        if (this.barNormalColor == value)
          return;
        this.barNormalColor = value;
        this.Invalidate();
      }
    }

    private Color barCurrentColor = Color.Tomato;
    /// <summary>
    ///导航栏当前颜色 
    /// </summary>
    [DefaultValue(typeof(Color), "Tomato")]
    [Description("导航栏当前颜色")]
    public Color BarCurrentColor
    {
      get { return this.barCurrentColor; }
      set
      {
        if (this.barCurrentColor == value)
          return;
        this.barCurrentColor = value;
        this.Invalidate();
      }
    }

    private DisplayImageCollection displayImageCollection;
    /// <summary>
    /// 要播放的图片集合
    /// </summary>
    [DefaultValue(null)]
    [Description("要播放的图片集合")]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DisplayImageCollection Images
    {
      get
      {
        if (this.displayImageCollection == null)
          this.displayImageCollection = new DisplayImageCollection(this);
        return this.displayImageCollection;
      }
    }

    private double animationTime = 500d;
    /// <summary>
    /// 动画播放的总时间
    /// </summary>
    [DefaultValue(500d)]
    [Description("动画播放的总时间(默认500毫秒)")]
    public double AnimationTime
    {
      get { return this.animationTime; }
      set
      {
        if (this.animationTime == value)
          return;
        this.animationTime = value;
      }
    }

    private int intervalTime = 1000;
    /// <summary>
    /// 图片轮播的时间间隔
    /// </summary>
    [DefaultValue(1000)]
    [Description("图片轮播的时间间隔(默认1000毫秒)")]
    public int IntervalTime
    {
      get { return this.intervalTime; }
      set
      {
        if (this.intervalTime == value)
          return;
        this.intervalTime = value;
      }
    }

    private int imageWidth = 400;
    /// <summary>
    ///图片框宽度 
    /// </summary>
    [DefaultValue(400)]
    [Description("图片框宽度")]
    public int ImageWidth
    {
      get { return this.imageWidth; }
      set
      {
        if (this.imageWidth == value)
          return;
        this.imageWidth = value;
        this.InitializeSlideDirection();
        this.InitializeDisplaySize();
        this.Invalidate();
      }
    }

    private int imageHeight = 200;
    /// <summary>
    ///图片框高度 
    /// </summary>
    [DefaultValue(200)]
    [Description("图片框高度")]
    public int ImageHeight
    {
      get { return this.imageHeight; }
      set
      {
        if (this.imageHeight == value)
          return;
        this.imageHeight = value;
        this.InitializeSlideDirection();
        this.InitializeDisplaySize();
        this.Invalidate();
      }
    }

    private SlideType slideDirection = SlideType.RightToLeft;
    /// <summary>
    ///滑动方向 
    /// </summary>
    [DefaultValue(SlideType.RightToLeft)]
    [Description("滑动方向")]
    public SlideType SlideDirection
    {
      get { return this.slideDirection; }
      set
      {
        if (this.slideDirection == value)
          return;
        this.slideDirection = value;
        this.InitializeSlideDirection();
        this.InitializeDisplaySize();
        this.Invalidate();
      }
    }

    private int imageDisplay = 1;
    /// <summary>
    ///显示区显示图片数量(最小值1)
    /// </summary>
    [DefaultValue(1)]
    [Description("显示区显示图片数量最小值1")]
    public int ImageDisplay
    {
      get { return this.imageDisplay; }
      set
      {
        if (this.imageDisplay == value || value < 1)
          return;
        this.imageDisplay = value;
        this.InitializeImageDisplay();
        this.InitializeDisplaySize();
        this.Invalidate();
      }
    }

    int currentImageIndex = -1;
    /// <summary>
    ///当前图片显示区第一张图片的索引 
    /// </summary>
    [Browsable(false)]
    [DefaultValue(-1)]
    [Description("当前图片显示区第一张图片的索引")]
    public int CurrentImageIndex
    {
      get { return this.currentImageIndex; }
      set
      {
        if (this.currentImageIndex == value)
          return;
        this.currentImageIndex = value;
      }
    }

    /// <summary>
    /// 图片框滑动距离
    /// </summary>
    private int distance = 0;

    /// <summary>
    /// 显示区中所有图片框集合
    /// </summary>
    private List<DisplayRectangleFItem> displayRectangleFItemList;

    /// <summary>
    /// 图片轮播的时间间隔累计(-1为动画正在切换中)
    /// </summary>
    private int intervalTimeValue = 0;

    /// <summary>
    /// 动画播放时间间隔定时器
    /// </summary>
    private Timer intervalTimer;

    /// <summary>
    /// 动画播放定时器
    /// </summary>
    private AnimationTimer animationTimer;

    #endregion

    public ImageCarouselExt()
    {
      SetStyle(ControlStyles.UserPaint, true);
      SetStyle(ControlStyles.AllPaintingInWmPaint, true);
      SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
      SetStyle(ControlStyles.ResizeRedraw, true);
      SetStyle(ControlStyles.SupportsTransparentBackColor, true);
      InitializeComponent();

      this.InitializeImageDisplay();
      this.InitializeSlideDirection();
      this.InitializeDisplaySize();

      this.intervalTimer = new Timer();
      this.intervalTimer.Interval = 50;
      this.intervalTimer.Tick += new EventHandler(this.intervalTimer_Tick);

      this.animationTimer = new AnimationTimer(this, new AnimationOptions());
      this.animationTimer.AnimationIng += new AnimationTimer.AnimationHandel(this.animationTimer_AnimationIng);
      this.animationTimer.AnimationEnding += new AnimationTimer.AnimationHandel(this.animationTimer_AnimationEnding);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
      base.OnPaint(e);

      Graphics g = e.Graphics;
      if (this.Images.Count > 0)
      {
        for (int i = 0; i < this.displayRectangleFItemList.Count; i++)
        {
          if (this.Images[this.displayRectangleFItemList[i].image_index].Image != null)
            g.DrawImage(this.Images[this.displayRectangleFItemList[i].image_index].Image, this.displayRectangleFItemList[i].current_rectf);
        }
        if (this.BarShow)
        {
          g.SmoothingMode = SmoothingMode.HighQuality;
          float w = 12;
          float h = 12;
          float interval = 5;
          float sum = (w + interval) * this.Images.Count - interval;
          float start_x = (e.ClipRectangle.Width - sum) / 2;
          float start_y = (e.ClipRectangle.Height - sum) / 2;
          SolidBrush barNormal_sb = new SolidBrush(Color.FromArgb(150, this.BarNormalColor));
          SolidBrush barCurrent_sb = new SolidBrush(Color.FromArgb(150, this.BarCurrentColor));
          for (int i = 0; i < this.Images.Count; i++)
          {
            RectangleF bar_rectf = new RectangleF(start_x + i * w + (i - 1) * interval, e.ClipRectangle.Height - h - 10, w, h);
            if (this.SlideDirection == SlideType.TopToBottom || this.SlideDirection == SlideType.BottomToTop)
            {
              bar_rectf = new RectangleF(e.ClipRectangle.Width - w - 10, start_y + i * h + (i - 1) * interval, w, h);
            }
            g.FillEllipse(i == this.CurrentImageIndex ? barCurrent_sb : barNormal_sb, bar_rectf);
          }
          barNormal_sb.Dispose();
          barCurrent_sb.Dispose();
        }

      }
    }

    /// <summary>
    /// 动画开始事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void intervalTimer_Tick(object sender, EventArgs e)
    {
      if (this.intervalTimeValue == -1)//动画进行中
        return;
      this.intervalTimeValue += this.intervalTimer.Interval;
      if (this.intervalTimeValue >= this.IntervalTime)
      {
        this.intervalTimeValue = -1;

        this.InitializeRectangle();

        this.animationTimer.AT = AnimationType.EaseOut;
        this.animationTimer.Options.Transform = this.distance;
        this.animationTimer.Options.AllTime = this.AnimationTime;
        this.animationTimer.Start(true, 0);
      }
    }

    /// <summary>
    /// 动画进行中事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void animationTimer_AnimationIng(object sender, AnimationEventArgs e)
    {
      float dis = (float)(e.Transform * e.progressTime);//计算动画值
      for (int i = 0; i < this.displayRectangleFItemList.Count; i++)
      {
        RectangleF current_rectf = new RectangleF(this.displayRectangleFItemList[i].v + dis, this.displayRectangleFItemList[i].current_rectf.Y, this.displayRectangleFItemList[i].current_rectf.Width, this.displayRectangleFItemList[i].current_rectf.Height);
        if (this.SlideDirection == SlideType.BottomToTop || this.SlideDirection == SlideType.TopToBottom)
        {
          current_rectf = new RectangleF(this.displayRectangleFItemList[i].current_rectf.X, this.displayRectangleFItemList[i].v + dis, this.displayRectangleFItemList[i].current_rectf.Width, this.displayRectangleFItemList[i].current_rectf.Height);
        }
        this.displayRectangleFItemList[i].current_rectf = current_rectf;
      }
      this.Invalidate();
    }

    /// <summary>
    /// 动画结束时事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void animationTimer_AnimationEnding(object sender, AnimationEventArgs e)
    {
      //动画结束时当前图片索引要移动
      if (this.SlideDirection == SlideType.RightToLeft || this.SlideDirection == SlideType.BottomToTop)
      {
        this.CurrentImageIndex += 1;
        if (this.CurrentImageIndex > this.Images.Count - 1)
          this.CurrentImageIndex = 0;
      }
      else
      {
        this.CurrentImageIndex -= 1;
        if (this.CurrentImageIndex < 0)
          this.CurrentImageIndex = this.Images.Count - 1; ;
      }

      this.intervalTimeValue = 0;
    }

    /// <summary>
    /// 初始化图片显示区大小
    /// </summary>
    private void InitializeDisplaySize()
    {
      if (this.SlideDirection == SlideType.RightToLeft || this.SlideDirection == SlideType.LeftToRight)
      {
        this.SetClientSizeCore(this.ImageWidth * this.ImageDisplay, this.ImageHeight);
      }
      else
      {
        this.SetClientSizeCore(this.ImageWidth, this.ImageHeight * this.ImageDisplay);
      }
    }

    /// <summary>
    /// 初始化图片框滑动距离
    /// </summary>
    private void InitializeSlideDirection()
    {
      switch (this.SlideDirection)
      {
        case SlideType.RightToLeft:
          {
            this.distance = -this.ImageWidth;
            break;
          }
        case SlideType.LeftToRight:
          {
            this.distance = this.ImageWidth;
            break;
          }
        case SlideType.BottomToTop:
          {
            this.distance = -this.ImageHeight;
            break;
          }
        case SlideType.TopToBottom:
          {
            this.distance = this.ImageHeight;
            break;
          }
      }

    }

    /// <summary>
    /// 初始化第一次播放时第一个图片框的图片索引
    /// </summary>
    private void InitializeCurrentIndex()
    {
      if (this.CurrentImageIndex != -1)
        return;
      if (this.SlideDirection == SlideType.RightToLeft || this.SlideDirection == SlideType.BottomToTop)
      {
        this.CurrentImageIndex = 0;
      }
      else
      {
        this.CurrentImageIndex = this.Images.Count - 1;
      }
    }

    /// <summary>
    /// 初始化滑动时要滑动的图片框数量
    /// </summary>
    private void InitializeImageDisplay()
    {
      this.displayRectangleFItemList = new List<DisplayRectangleFItem>();
      for (int i = 0; i < this.ImageDisplay + 1; i++)
      {
        this.displayRectangleFItemList.Add(new DisplayRectangleFItem());
      }
    }

    /// <summary>
    /// 初始化播放前每一个图片框的信息
    /// </summary>
    private void InitializeRectangle()
    {
      this.InitializeCurrentIndex();

      if (this.SlideDirection == SlideType.RightToLeft || this.SlideDirection == SlideType.BottomToTop)
      {
        for (int i = 0; i < this.displayRectangleFItemList.Count; i++)
        {
          this.displayRectangleFItemList[i].v = i * -this.distance;
          if (this.SlideDirection == SlideType.RightToLeft)
          {
            this.displayRectangleFItemList[i].current_rectf = new RectangleF(this.displayRectangleFItemList[i].v, 0, this.ImageWidth, this.ImageHeight);
          }
          else
          {
            this.displayRectangleFItemList[i].current_rectf = new RectangleF(0, this.displayRectangleFItemList[i].v, this.ImageWidth, this.ImageHeight);
          }
          this.displayRectangleFItemList[i].image_index = this.currentImageIndex + i;
          while (this.displayRectangleFItemList[i].image_index > this.Images.Count - 1)
          {
            this.displayRectangleFItemList[i].image_index -= this.Images.Count;
          }
        }
      }
      else
      {
        for (int i = this.displayRectangleFItemList.Count - 1; i >= 0; i--)
        {
          this.displayRectangleFItemList[i].v = (i == 0) ? -this.distance : (i - 1) * this.distance;
          if (this.SlideDirection == SlideType.LeftToRight)
          {
            this.displayRectangleFItemList[i].current_rectf = new RectangleF(this.displayRectangleFItemList[i].v, 0, this.ImageWidth, this.ImageHeight);
          }
          else
          {
            this.displayRectangleFItemList[i].current_rectf = new RectangleF(0, this.displayRectangleFItemList[i].v, this.ImageWidth, this.ImageHeight);
          }
          this.displayRectangleFItemList[i].image_index = this.currentImageIndex - (this.displayRectangleFItemList.Count - 1 - i);
          while (this.displayRectangleFItemList[i].image_index < 0)
          {
            this.displayRectangleFItemList[i].image_index += this.Images.Count;
          }
        }
      }
    }

    /// <summary>
    /// 开始轮播图片
    /// </summary>
    public void Play()
    {
      this.intervalTimer.Enabled = true;
    }

    /// <summary>
    /// 停止轮播图片
    /// </summary>
    public void Stop()
    {
      this.intervalTimer.Enabled = false;
    }

    protected override void Dispose(bool disposing)
    {
      if (disposing && (components != null))
      {
        components.Dispose();
        if (this.intervalTimer != null)
        {
          this.intervalTimer.Dispose();
        }
        if (this.animationTimer != null)
        {
          this.animationTimer.Dispose();
        }
      }
      base.Dispose(disposing);
    }

    /// <summary>
    /// 鱼眼菜单选项集合
    /// </summary>
    [Description("鱼眼菜单选项集合")]
    [Editor(typeof(CollectionEditorExt), typeof(UITypeEditor))]
    public sealed class DisplayImageCollection : IList, ICollection, IEnumerable
    {
      private ArrayList displayImageList = new ArrayList();
      private ImageCarouselExt owner;

      public DisplayImageCollection(ImageCarouselExt owner)
      {
        this.owner = owner;
      }

      #region IEnumerable

      public IEnumerator GetEnumerator()
      {
        DisplayImage[] listArray = new DisplayImage[this.displayImageList.Count];
        for (int index = 0; index < listArray.Length; ++index)
          listArray[index] = (DisplayImage)this.displayImageList[index];
        return listArray.GetEnumerator();
      }

      #endregion

      #region ICollection

      public void CopyTo(Array array, int index)
      {
        for (int i = 0; i < this.Count; i++)
          array.SetValue(this.displayImageList[i], i + index);
      }

      public int Count
      {
        get
        {
          return this.displayImageList.Count;
        }
      }

      public bool IsSynchronized
      {
        get
        {
          return false;
        }
      }

      public object SyncRoot
      {
        get
        {
          return (object)this;
        }
      }

      #endregion

      #region IList

      public int Add(object value)
      {
        DisplayImage displayImage = (DisplayImage)value;
        this.displayImageList.Add(displayImage);
        this.owner.Invalidate();
        return this.Count - 1;
      }

      public void Clear()
      {
        this.displayImageList.Clear();
        this.owner.Invalidate();
      }

      public bool Contains(object value)
      {
        return this.IndexOf(value) != -1;
      }

      public int IndexOf(object value)
      {
        return this.displayImageList.IndexOf(value);
      }

      public void Insert(int index, object value)
      {
        throw new NotImplementedException();
      }

      public bool IsFixedSize
      {
        get { return false; }
      }

      public bool IsReadOnly
      {
        get { return false; }
      }

      public void Remove(object value)
      {
        if (!(value is DisplayImage))
          return;
        this.displayImageList.Remove((DisplayImage)value);
        this.owner.Invalidate();
      }

      public void RemoveAt(int index)
      {
        this.displayImageList.RemoveAt(index);
        this.owner.Invalidate();
      }

      public DisplayImage this[int index]
      {
        get
        {
          if (index > this.Count - 1)
            return null;
          return (DisplayImage)this.displayImageList[index];
        }
        set
        {
          this.displayImageList[index] = (DisplayImage)value;
          this.owner.Invalidate();
        }
      }

      object IList.this[int index]
      {
        get
        {
          return (object)this.displayImageList[index];
        }
        set
        {
          this.displayImageList[index] = (DisplayImage)value;
          this.owner.Invalidate();
        }
      }

      #endregion

    }

    /// <summary>
    /// 显示区图片
    /// </summary>
    [Description("显示区图片")]
    public class DisplayImage
    {
      /// <summary>
      /// 图片
      /// </summary>
      [Description("图片")]
      public Image Image { get; set; }
    }

    /// <summary>
    /// 滑动方向
    /// </summary>
    [Description("滑动方向")]
    public enum SlideType
    {
      /// <summary>
      /// 由右往左
      /// </summary>
      RightToLeft,
      /// <summary>
      /// 由左往右
      /// </summary>
      LeftToRight,
      /// <summary>
      /// 由下往上
      /// </summary>
      BottomToTop,
      /// <summary>
      /// 由上往下
      /// </summary>
      TopToBottom
    }

    /// <summary>
    /// 显示区rectf选项
    /// </summary>
    [Description("显示区rectf选项")]
    public class DisplayRectangleFItem
    {
      /// <summary>
      /// 运动前坐标
      /// </summary>
      [Browsable(false)]
      [Description("运动前坐标")]
      public float v { get; set; }

      /// <summary>
      /// 当前rectf
      /// </summary>
      [Browsable(false)]
      [Description("当前rectf")]
      public RectangleF current_rectf { get; set; }

      /// <summary>
      /// rectf对应指定Images中索引的Image
      /// </summary>
      [Browsable(false)]
      [Description("rectf对应指定Images中索引的Image")]
      public int image_index { get; set; }
    }

  }

 

 源码下载:CSharp走马灯图片轮播控件.zip

转载于:https://www.cnblogs.com/tlmbem/p/11331389.html

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值