GDI不规则圆弧菜单控件----------WinForm控件开发系列

GDI不规则圆弧菜单控件----------WinForm控件开发系列

  /// <summary>
  /// 圆弧菜单控件
  /// </summary>
  [ToolboxItem(true)]
  [DefaultProperty("Items")]
  [DefaultEvent("RadianMenuItemClick")]
  [Description("圆弧菜单控件")]
  public partial class RadianMenuExt : Control
  {
    public delegate void EventHandler(object sender, RadianMenuItemEventArgs e);

    private event EventHandler radianMenuItemClick;
    /// <summary>
    /// 鱼眼菜单单击事件
    /// </summary>
    [Description("鱼眼菜单单击事件")]
    public event EventHandler RadianMenuItemClick
    {
      add { this.radianMenuItemClick += value; }
      remove { this.radianMenuItemClick -= value; }
    }

    #region

    private int circleRadius = 50;
    /// <summary>
    /// 圆半径
    /// </summary>
    [DefaultValue(50)]
    [Description("圆半径(默认50)")]
    public int CircleRadius
    {
      get { return this.circleRadius; }
      set
      {
        if (this.circleRadius == value || value < 0)
          return;
        this.circleRadius = value;
        this.InitializeRadian();
        this.Invalidate();
      }
    }

    private int radianOpacity = 150;
    /// <summary>
    /// 圆弧透明度
    /// </summary>
    [DefaultValue(150)]
    [Description("圆弧透明度(默认150)")]
    public int RadianOpacity
    {
      get { return this.radianOpacity; }
      set
      {
        if (this.radianOpacity == value || this.radianOpacity < 0 || this.radianOpacity > 255)
          return;
        this.radianOpacity = value;
        this.Invalidate();
      }
    }

    private int radianTextOpacity = 220;
    /// <summary>
    /// 圆弧文字透明度
    /// </summary>
    [DefaultValue(220)]
    [Description("圆弧文字透明度(默认220)")]
    public int RadianTextOpacity
    {
      get { return this.radianTextOpacity; }
      set
      {
        if (this.radianTextOpacity == value || this.radianTextOpacity < 0 || this.radianTextOpacity > 255)
          return;
        this.radianTextOpacity = value;
        this.Invalidate();
      }
    }

    private int radianWidth = 70;
    /// <summary>
    /// 圆弧宽度
    /// </summary>
    [DefaultValue(70)]
    [Description("圆弧宽度(默认70)")]
    public int RadianWidth
    {
      get { return this.radianWidth; }
      set
      {
        if (this.radianWidth == value || value < 0)
          return;
        this.radianWidth = value;
        this.InitializeRadian();
        this.Invalidate();
      }
    }

    private int radianWidthLargen = 20;
    /// <summary>
    /// 圆弧宽度放大值
    /// </summary>
    [DefaultValue(20)]
    [Description("圆弧宽度放大值(默认20)")]
    public int RadianWidthLargen
    {
      get { return this.radianWidthLargen; }
      set
      {
        if (this.radianWidthLargen == value || value < 0)
          return;
        this.radianWidthLargen = value;
        this.InitializeRadian();
        this.Invalidate();
      }
    }

    private int radianLargenTime = 350;
    /// <summary>
    /// 圆弧放大缩小动画播放的总时间
    /// </summary>
    [DefaultValue(350)]
    [Description("圆弧放大缩小动画播放的总时间(默认350毫秒)")]
    public int RadianLargenTime
    {
      get
      {
        return this.radianLargenTime;
      }
      set
      {
        if (this.radianLargenTime == value || value < 0)
          return;
        this.radianLargenTime = value;
        for (int i = 0; i < this.Items.Count; i++)
        {
          this.Items[i].Animation.Options.AllTime = value;
        }
      }
    }

    private bool radianRotate = false;
    /// <summary>
    /// 圆弧是否旋转动画
    /// </summary>
    [DefaultValue(false)]
    [Description("圆弧旋转动画(默认false)")]
    public bool RadianRotate
    {
      get { return this.radianRotate; }
      set
      {
        if (this.radianRotate == value)
          return;
        this.radianRotate = value;
        if (value)
          this.InitializeRadianAnimation();
        else
          this.UnInitializeRadianAnimation();
      }
    }

    private int radianRotateTime = 1000;
    /// <summary>
    /// 圆弧旋转动画播放的总时间
    /// </summary>
    [DefaultValue(1000)]
    [Description("圆弧动画播放的总时间(默认1000毫秒)")]
    public int RadianRotateTime
    {
      get { return this.radianRotateTime; }
      set
      {
        if (this.radianRotateTime == value)
          return;
        this.radianRotateTime = value;
        for (int i = 0; i < this.Items.Count; i++)
        {
          this.Items[i].RadianAnimation.Options.AllTime = value;
        }
      }
    }

    private RadianMenuItemCollection radianMenuItemCollection;
    /// <summary>
    /// 圆弧选项配置列表
    /// </summary>
    [Description("圆弧选项配置列表")]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public RadianMenuItemCollection Items
    {
      get
      {
        if (this.radianMenuItemCollection == null)
          this.radianMenuItemCollection = new RadianMenuItemCollection(this);
        return this.radianMenuItemCollection;
      }
    }

    protected override Size DefaultSize
    {
      get
      {
        return new Size(450, 450);
      }
    }

    /// <summary>
    /// 选中圆弧选项
    /// </summary>
    private RadianMenuItem selectedItem = null;

    #endregion

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

    }

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

      Graphics g = e.Graphics;
      g.TextRenderingHint = TextRenderingHint.AntiAlias;

      for (int i = 0; i < this.Items.Count; i++)
      {
        SolidBrush radian_sb = new SolidBrush(Color.FromArgb(this.RadianOpacity, this.Items[i].RadianColor));
        g.FillRegion(radian_sb, this.Items[i].RadianRegion);
        radian_sb.Dispose();

        if (!String.IsNullOrWhiteSpace(Items[i].Text))//文本
        {
          SolidBrush text_sb = new SolidBrush(Color.FromArgb(this.RadianTextOpacity, this.Items[i].TextColor));
          SizeF str_size = g.MeasureString(this.Items[i].Text, this.Items[i].TextFont);
          if (i == 0)//圆心
          {
            str_size = new SizeF(str_size.Width + 2f, str_size.Height + 2f);
            g.DrawString(this.Items[i].Text, this.Items[i].TextFont, text_sb, new RectangleF(this.Items[i].RadianNowRectF.X + (this.Items[i].RadianNowRectF.Width - str_size.Width) / 2, this.Items[i].RadianNowRectF.Y + (this.Items[i].RadianNowRectF.Height - str_size.Height) / 2, str_size.Width, str_size.Height));

          }
          else//圆弧
          {
            SizeF ds = new System.Drawing.SizeF(this.Items[i].RadianNowRectF.Width - (this.Items[i].RadianMaxRectF.Width - this.Items[i].RadianNormalRectF.Width) / 2, this.Items[i].RadianNowRectF.Height - (this.Items[i].RadianMaxRectF.Height - this.Items[i].RadianNormalRectF.Height) / 2);

            double degrees = 1 / ((2 * Math.PI * this.Items[i].RadianNowRectF.Width / 2) / 360);//一度弧长
            double angle = degrees * ((str_size.Width / this.Items[i].Text.Length) + 4);//一弧长角度

            g.TranslateTransform(this.Width / 2, this.Height / 2);//更改起始坐标
            g.RotateTransform(90 + this.Items[i].RadianNowStartAngle);//更改起始角度

            for (int j = 0; j < this.Items[i].Text.Length; j++)
            {
              g.RotateTransform((float)angle);
              g.DrawString(this.Items[i].Text[j].ToString(), this.Items[i].TextFont, text_sb, 0, -this.Items[i].RadianNowRectF.Height / 2 + str_size.Height / 2);
            }

            g.RotateTransform((float)((this.Items[i].Text.Length * -angle)));
            g.RotateTransform(-(90 + this.Items[i].RadianNowStartAngle));
            g.TranslateTransform(-this.Width / 2, -this.Height / 2);//更改起始坐标
          }
          text_sb.Dispose();
        }
      }
    }

    protected override void OnResize(EventArgs e)
    {
      base.OnResize(e);

      this.InitializeRadian();
    }

    protected override void OnClick(EventArgs e)
    {
      base.OnClick(e);
      if (this.selectedItem != null && this.radianMenuItemClick != null)
      {
        this.radianMenuItemClick(this, new RadianMenuItemEventArgs() { Item = this.selectedItem });
      }
    }

    /// <summary>
    /// 鼠标进入离开
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected override void OnMouseMove(MouseEventArgs e)
    {
      base.OnMouseMove(e);

      for (int i = 0; i < this.Items.Count; i++)
      {
        if (this.Items[i].RadianRegion.IsVisible(e.Location))//鼠标进入
        {
          if (this.Items[i].RadianMoveState == MoveState.Leave)
          {
            this.selectedItem = this.Items[i];
            this.Items[i].RadianMoveState = MoveState.EnterAnimation;

            this.Items[i].Animation.AT = AnimationType.ElasticOut;
            this.Items[i].Animation.Options.AllTime = this.RadianLargenTime;
            this.Items[i].Animation.Start(true, this.Items[i].Animation.UsedTime);
          }
        }
        else//鼠标离开
        {
          if (this.Items[i].RadianMoveState == MoveState.Enter || this.Items[i].RadianMoveState == MoveState.EnterAnimation)
          {
            if (this.selectedItem != null && this.selectedItem.Equals(this.Items[i]))
              this.selectedItem = null;
            this.Items[i].RadianMoveState = MoveState.LeaveAnimation;

            this.Items[i].Animation.AT = AnimationType.BackIn;
            this.Items[i].Animation.Options.AllTime = this.RadianLargenTime;
            this.Items[i].Animation.Start(false, this.Items[i].Animation.UsedTime);
          }
        }
      }
    }
    /// <summary>
    /// 鼠标离开可视区
    /// </summary>
    /// <param name="e"></param>
    protected override void OnMouseLeave(EventArgs e)
    {
      base.OnMouseLeave(e);
      this.selectedItem = null;
    }

    /// <summary>
    /// 缩放动画进行中
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Animation_AnimationIng(object sender, AnimationEventArgs e)
    {
      RadianMenuItem rmi = (RadianMenuItem)e.Data;
      float w = (float)(rmi.RadianNormalRectF.Width + (rmi.RadianMaxRectF.Width - rmi.RadianNormalRectF.Width) * e.progressTime);
      float h = (float)(rmi.RadianNormalRectF.Height + (rmi.RadianMaxRectF.Height - rmi.RadianNormalRectF.Height) * e.progressTime);
      float x = (this.ClientRectangle.Width - w) / 2;
      float y = (this.ClientRectangle.Height - h) / 2;
      rmi.RadianNowRectF = new RectangleF(x, y, w, h);
      float v = (float)((rmi.RadianMaxWidth - rmi.RadianNormalWidth) * e.progressTime);
      rmi.RadianNowWidth = (int)(rmi.RadianNormalWidth + v);

      int index = this.Items.IndexOf(rmi);
      if (index == 0)
      {
        GraphicsPath gp1 = new GraphicsPath();
        gp1.AddEllipse(rmi.RadianNowRectF);
        Region r = new Region(gp1);
        rmi.RadianRegion = r;
        gp1.Dispose();
      }
      else
      {
        GraphicsPath gp1 = new GraphicsPath();
        GraphicsPath gp2 = new GraphicsPath();
        gp1.AddPie(rmi.RadianNowRectF.X, rmi.RadianNowRectF.Y, rmi.RadianNowRectF.Width, rmi.RadianNowRectF.Height, rmi.RadianNowStartAngle, rmi.RadianSweepAngle);
        gp2.AddPie(rmi.RadianNowRectF.X + rmi.RadianNowWidth / 2, rmi.RadianNowRectF.Y + rmi.RadianNowWidth / 2, rmi.RadianNowRectF.Width - rmi.RadianNowWidth, rmi.RadianNowRectF.Height - rmi.RadianNowWidth, 0f, 360f);
        Region r = new Region(gp1);
        r.Exclude(gp2);
        rmi.RadianRegion = r;
        gp1.Dispose();
        gp2.Dispose();
      }

      this.Invalidate();
    }
    /// <summary>
    /// 缩放动画结束
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Animation_AnimationEnding(object sender, AnimationEventArgs e)
    {
      RadianMenuItem rmi = (RadianMenuItem)e.Data;
      if (rmi.RadianMoveState == MoveState.LeaveAnimation)
      {
        rmi.RadianMoveState = MoveState.Leave;
      }
      else if (rmi.RadianMoveState == MoveState.EnterAnimation)
      {
        rmi.RadianMoveState = MoveState.Enter;
      }
    }

    /// <summary>
    /// 旋转动画进行中
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void RadianAnimation_AnimationIng(object sender, AnimationEventArgs e)
    {
      RadianMenuItem rmi = (RadianMenuItem)e.Data;
      if (rmi.RadianMoveState == MoveState.Leave)
      {
        float original = 0f;
        if (rmi.RadianRotateValue < 0)//旋转方向
        {
          original = rmi.RadianAnimation.Options.Transform < 0 ? rmi.RadianStartAngle : (rmi.RadianStartAngle + rmi.RadianRotateValue);
        }
        else
        {
          original = rmi.RadianAnimation.Options.Transform > 0 ? rmi.RadianStartAngle : (rmi.RadianStartAngle + rmi.RadianRotateValue);
        }
        rmi.RadianNowStartAngle = (int)(original + e.Transform * e.progressTime);


        GraphicsPath gp1 = new GraphicsPath();
        GraphicsPath gp2 = new GraphicsPath();
        gp1.AddPie(rmi.RadianNormalRectF.X, rmi.RadianNormalRectF.Y, rmi.RadianNormalRectF.Width, rmi.RadianNormalRectF.Height, rmi.RadianNowStartAngle, rmi.RadianSweepAngle);
        gp2.AddPie(rmi.RadianNormalRectF.X + rmi.RadianNormalWidth / 2, rmi.RadianNormalRectF.Y + rmi.RadianNormalWidth / 2, rmi.RadianNormalRectF.Width - rmi.RadianNormalWidth, rmi.RadianNormalRectF.Height - rmi.RadianNormalWidth, 0f, 360f);
        Region r = new Region(gp1);
        r.Exclude(gp2);
        rmi.RadianRegion = r;
        gp1.Dispose();
        gp2.Dispose();

        this.Invalidate();
      }
    }
    /// <summary>
    /// 旋转动画间隔重复事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void RadianAnimation_AnimationRepetitioning(object sender, AnimationEventArgs e)
    {
      RadianMenuItem rmi = (RadianMenuItem)e.Data;
      rmi.RadianAnimation.Options.Transform = -1 * rmi.RadianAnimation.Options.Transform;
    }

    /// <summary>
    /// 初始化圆弧控件大小位置
    /// </summary>
    private void InitializeRadian()
    {
      int diameter = this.CircleRadius * 2;//直径

      for (int i = 0; i < this.Items.Count; i++)
      {
        if (i == 0)
        {
          float w = diameter;
          float h = diameter;
          float x = (this.ClientRectangle.Width - w) / 2;
          float y = (this.ClientRectangle.Height - h) / 2;

          float max_w = w + this.RadianWidthLargen;
          float max_h = h + this.RadianWidthLargen;
          float max_x = (this.ClientRectangle.Width - max_w) / 2;
          float max_y = (this.ClientRectangle.Height - max_h) / 2;

          this.Items[i].RadianNormalRectF = new RectangleF(x, y, w, h);
          this.Items[i].RadianMaxRectF = new RectangleF(max_x, max_y, max_w, max_h);
          this.Items[i].RadianNowRectF = this.Items[i].RadianNormalRectF;

          GraphicsPath gp1 = new GraphicsPath();
          gp1.AddEllipse(this.Items[i].RadianNormalRectF);
          Region r = new Region(gp1);
          this.Items[i].RadianRegion = r;
          gp1.Dispose();
        }
        else
        {
          float w = diameter + this.RadianWidth * i;
          float h = diameter + this.RadianWidth * i;
          float x = (this.ClientRectangle.Width - w) / 2;
          float y = (this.ClientRectangle.Height - h) / 2;

          float max_w = w + this.RadianWidthLargen;
          float max_h = h + this.RadianWidthLargen;
          float max_x = (this.ClientRectangle.Width - max_w) / 2;
          float max_y = (this.ClientRectangle.Height - max_h) / 2;

          this.Items[i].RadianNormalRectF = new RectangleF(x, y, w, h);
          this.Items[i].RadianMaxRectF = new RectangleF(max_x, max_y, max_w, max_h);
          this.Items[i].RadianNowRectF = this.Items[i].RadianNormalRectF;

          this.Items[i].RadianNormalWidth = this.RadianWidth;
          this.Items[i].RadianMaxWidth = this.RadianWidth + this.RadianWidthLargen;
          this.Items[i].RadianNowWidth = this.RadianWidth;
          this.Items[i].RadianNowStartAngle = this.Items[i].RadianStartAngle;

          GraphicsPath gp1 = new GraphicsPath();
          GraphicsPath gp2 = new GraphicsPath();
          gp1.AddPie(this.Items[i].RadianNormalRectF.X, this.Items[i].RadianNormalRectF.Y, this.Items[i].RadianNormalRectF.Width, this.Items[i].RadianNormalRectF.Height, this.Items[i].RadianNowStartAngle, this.Items[i].RadianSweepAngle);
          gp2.AddPie(this.Items[i].RadianNormalRectF.X + this.Items[i].RadianNormalWidth / 2, this.Items[i].RadianNormalRectF.Y + this.Items[i].RadianNormalWidth / 2, this.Items[i].RadianNormalRectF.Width - this.Items[i].RadianNormalWidth, this.Items[i].RadianNormalRectF.Height - this.Items[i].RadianNormalWidth, 0f, 360f);
          Region r = new Region(gp1);
          r.Exclude(gp2);
          this.Items[i].RadianRegion = r;
          gp1.Dispose();
          gp2.Dispose();
        }
        if (this.Items[i].Animation == null)
        {
          this.Items[i].Animation = new AnimationTimer(this, new AnimationOptions());
          this.Items[i].Animation.Options.Data = this.Items[i];
          this.Items[i].Animation.AnimationIng += new AnimationTimer.AnimationHandel(this.Animation_AnimationIng);
          this.Items[i].Animation.AnimationEnding += new AnimationTimer.AnimationHandel(this.Animation_AnimationEnding);
        }
      }
    }

    /// <summary>
    /// 加载旋转动画
    /// </summary>
    private void InitializeRadianAnimation()
    {
      for (int i = 1; i < this.Items.Count; i++)
      {
        if (this.Items[i].RadianRotateValue != 0)
        {
          this.Items[i].RadianAnimation = new AnimationTimer(this, new AnimationOptions());
          this.Items[i].RadianAnimation.AnimationIng += new AnimationTimer.AnimationHandel(this.RadianAnimation_AnimationIng);
          this.Items[i].RadianAnimation.AnimationRepetitioning += new AnimationTimer.AnimationHandel(this.RadianAnimation_AnimationRepetitioning);

          this.Items[i].RadianAnimation.Options.AlwaysRepetitionExercise = true;
          this.Items[i].RadianAnimation.Options.Data = this.Items[i];
          this.Items[i].RadianAnimation.Options.Transform = this.Items[i].RadianRotateValue;
          this.Items[i].RadianAnimation.Options.AllTime = this.RadianRotateTime;
          this.Items[i].RadianAnimation.AT = AnimationType.UniformMotion;
          this.Items[i].RadianAnimation.Start(true, 0);
        }
      }
    }

    /// <summary>
    /// 卸载旋转动画
    /// </summary>
    private void UnInitializeRadianAnimation()
    {
      for (int i = 1; i < this.Items.Count; i++)
      {
        if (this.Items[i].RadianRotateValue != 0)
        {
          this.Items[i].RadianAnimation.Dispose();
          this.Items[i].RadianAnimation = null;
        }
      }
    }

    protected override void Dispose(bool disposing)
    {
      if (disposing && (components != null))
      {
        components.Dispose();
        for (int i = 0; i < this.Items.Count; i++)
        {
          if (this.Items[i].Animation != null)
          {
            this.Items[i].Animation.Dispose();
          }
          if (this.Items[i].RadianAnimation != null)
          {
            this.Items[i].RadianAnimation.Dispose();
          }
        }
      }
      base.Dispose(disposing);
    }

    /// <summary>
    /// 圆弧选项集合
    /// </summary>
    [Description("圆弧选项集合")]
    [Editor(typeof(CollectionEditorExt), typeof(UITypeEditor))]
    public sealed class RadianMenuItemCollection : IList, ICollection, IEnumerable
    {
      private ArrayList radianMenuItemList = new ArrayList();
      private RadianMenuExt owner;

      public RadianMenuItemCollection(RadianMenuExt owner)
      {
        this.owner = owner;
      }

      #region IEnumerable

      public IEnumerator GetEnumerator()
      {
        RadianMenuItem[] listArray = new RadianMenuItem[this.radianMenuItemList.Count];
        for (int index = 0; index < listArray.Length; ++index)
          listArray[index] = (RadianMenuItem)this.radianMenuItemList[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.radianMenuItemList[i], i + index);
      }

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

      public bool IsSynchronized
      {
        get
        {
          return false;
        }
      }

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

      #endregion

      #region IList

      public int Add(object value)
      {
        RadianMenuItem radianMenuItem = (RadianMenuItem)value;
        this.radianMenuItemList.Add(radianMenuItem);
        this.owner.InitializeRadian();
        this.owner.Invalidate();
        return this.Count - 1;
      }

      public void Clear()
      {
        for (int i = 0; i < this.Count; i++)
        {
          RadianMenuItem item = (RadianMenuItem)this.radianMenuItemList[i];
          item.Animation.Dispose();
          item.Animation = null;
          item.RadianAnimation.Dispose();
          item.RadianAnimation = null;
          item.RadianRegion.Dispose();
          item.TextFont.Dispose();
        }
        this.radianMenuItemList.Clear();
        this.owner.InitializeRadian();
        this.owner.Invalidate();
      }

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

      public int IndexOf(object value)
      {
        return this.radianMenuItemList.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 RadianMenuItem))
          return;

        RadianMenuItem item = (RadianMenuItem)value;
        item.Animation.Dispose();
        item.Animation = null;
        item.RadianAnimation.Dispose();
        item.RadianAnimation = null;
        item.RadianRegion.Dispose();
        item.TextFont.Dispose();
        this.radianMenuItemList.Remove((RadianMenuItem)value);
        this.owner.InitializeRadian();
        this.owner.Invalidate();
      }

      public void RemoveAt(int index)
      {
        RadianMenuItem item = (RadianMenuItem)this.radianMenuItemList[index];
        item.Animation.Dispose();
        item.Animation = null;
        item.RadianAnimation.Dispose();
        item.RadianAnimation = null;
        item.RadianRegion.Dispose();
        item.TextFont.Dispose();
        this.radianMenuItemList.RemoveAt(index);
        this.owner.InitializeRadian();
        this.owner.Invalidate();
      }

      public RadianMenuItem this[int index]
      {
        get
        {
          return (RadianMenuItem)this.radianMenuItemList[index];
        }
        set
        {
          this.radianMenuItemList[index] = (RadianMenuItem)value;
          this.owner.InitializeRadian();
          this.owner.Invalidate();
        }
      }

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

      #endregion

    }

    /// <summary>
    /// 圆弧选项
    /// </summary>
    [Description("圆弧选项")]
    public class RadianMenuItem
    {
      private AnimationTimer animation = null;
      /// <summary>
      /// 缩放动画对象
      /// </summary>
      [Browsable(false)]
      [DefaultValue(null)]
      [Description("缩放动画对象")]
      public AnimationTimer Animation
      {
        get { return this.animation; }
        set
        {
          if (this.animation == value)
            return;
          this.animation = value;
        }
      }

      private AnimationTimer radianAnimation = null;
      /// <summary>
      /// 旋转动画对象
      /// </summary>
      [Browsable(false)]
      [DefaultValue(null)]
      [Description("旋转动画对象")]
      public AnimationTimer RadianAnimation
      {
        get { return this.radianAnimation; }
        set
        {
          if (this.radianAnimation == value)
            return;
          this.radianAnimation = value;
        }
      }

      private RectangleF radianNormalRectF;
      /// <summary>
      /// 圆弧选项默认Rect
      /// </summary>
      [Browsable(false)]
      [Description("圆弧选项默认Rect")]
      public RectangleF RadianNormalRectF
      {
        get { return this.radianNormalRectF; }
        set
        {
          if (this.radianNormalRectF == value)
            return;
          this.radianNormalRectF = value;
        }
      }

      private RectangleF radianMaxRectF;
      /// <summary>
      /// 圆弧选项最大Rect
      /// </summary>
      [Browsable(false)]
      [Description("圆弧选项最大Rect")]
      public RectangleF RadianMaxRectF
      {
        get { return this.radianMaxRectF; }
        set
        {
          if (this.radianMaxRectF == value)
            return;
          this.radianMaxRectF = value;
        }
      }

      private RectangleF radianNowRectF;
      /// <summary>
      /// 圆弧选项当前Rect
      /// </summary>
      [Browsable(false)]
      [Description("圆弧选项当前Rect")]
      public RectangleF RadianNowRectF
      {
        get { return this.radianNowRectF; }
        set
        {
          if (this.radianNowRectF == value)
            return;
          this.radianNowRectF = value;
        }
      }

      private Region radianRegion = new Region();
      /// <summary>
      /// 圆弧选项Region
      /// </summary>
      [Browsable(false)]
      [Description("圆弧选项Region")]
      public Region RadianRegion
      {
        get { return this.radianRegion; }
        set
        {
          if (this.radianRegion == value)
            return;
          this.radianRegion = value;
        }
      }

      private MoveState radianMoveState = MoveState.Leave;
      /// <summary>
      /// 圆弧选项鼠标状态
      /// </summary>
      [Browsable(false)]
      [Description("圆弧选项鼠标状态")]
      public MoveState RadianMoveState
      {
        get { return this.radianMoveState; }
        set
        {
          if (this.radianMoveState == value)
            return;
          this.radianMoveState = value;
        }
      }

      private string text;
      /// <summary>
      /// 圆弧选项文本
      /// </summary>
      [Browsable(true)]
      [Description("圆弧选项文本")]
      public string Text
      {
        get { return this.text; }
        set
        {
          if (this.text == value)
            return;
          this.text = value;
        }
      }

      private Font textFont = new Font("幼圆", 12, FontStyle.Bold);
      /// <summary>
      /// 文本字体
      /// </summary>
      [Browsable(true)]
      [DefaultValue(typeof(Font), "幼圆, 12pt, style=Bold")]
      [Description("文本字体")]
      public Font TextFont
      {
        get { return this.textFont; }
        set
        {
          if (this.textFont == value)
            return;
          this.textFont = value;
        }
      }

      private Color textColor = Color.White;
      /// <summary>
      /// 文本字体颜色
      /// </summary>
      [Browsable(true)]
      [DefaultValue(typeof(Color), "White")]
      [Description("文本字体颜色")]
      public Color TextColor
      {
        get { return this.textColor; }
        set
        {
          if (this.textColor == value)
            return;
          this.textColor = value;
        }
      }

      private Color radianColor = Color.Empty;
      /// <summary>
      /// 圆弧颜色
      /// </summary>
      [Browsable(true)]
      [DefaultValue(typeof(Color), "Empty")]
      [Description("圆弧颜色")]
      public Color RadianColor
      {
        get { return this.radianColor; }
        set
        {
          if (this.radianColor == value)
            return;
          this.radianColor = value;
        }
      }

      private float radianStartAngle = 0f;
      /// <summary>
      ///  圆弧开始角度
      /// </summary>
      [Browsable(true)]
      [DefaultValue(0f)]
      [Description("圆弧开始角度")]
      public float RadianStartAngle
      {
        get { return this.radianStartAngle; }
        set
        {
          if (this.radianStartAngle == value || value < -360 || value > 360)
            return;
          this.radianStartAngle = value;
        }
      }

      private float radianSweepAngle = 90f;
      /// <summary>
      /// 圆弧从 RadianStartAngle 参数到圆弧的结束点沿顺时针方向度量的角(以度为单位)。
      /// </summary>
      [Browsable(true)]
      [DefaultValue(90f)]
      [Description("圆弧从 RadianStartAngle 参数到圆弧的结束点沿顺时针方向度量的角(以度为单位)。")]
      public float RadianSweepAngle
      {
        get { return this.radianSweepAngle; }
        set
        {
          if (this.radianSweepAngle == value || value < -360 || value > 360)
            return;
          this.radianSweepAngle = value;
        }
      }

      private int radianRotateValue = 0;
      /// <summary>
      /// 圆弧要旋转的角度(-180至180)
      /// </summary>
      [Browsable(true)]
      [DefaultValue(0)]
      [Description("弧度要旋转的角度(-180至180)(默认0)")]
      public int RadianRotateValue
      {
        get { return this.radianRotateValue; }
        set
        {
          if (this.radianRotateValue == value || value < -180 || value > 180)
            return;
          this.radianRotateValue = value;
        }
      }

      private float radianNowStartAngle;
      /// <summary>
      /// 当前圆弧开始角度
      /// </summary>
      [Browsable(false)]
      [Description("当前圆弧开始角度")]
      public float RadianNowStartAngle
      {
        get { return this.radianNowStartAngle; }
        set
        {
          if (this.radianNowStartAngle == value || value < -360 || value > 360)
            return;
          this.radianNowStartAngle = value;
        }
      }

      private int radianNormalWidth;
      /// <summary>
      /// 圆弧默认宽度
      /// </summary>
      [Browsable(false)]
      [Description("圆弧默认宽度")]
      public int RadianNormalWidth
      {
        get { return this.radianNormalWidth; }
        set
        {
          if (this.radianNormalWidth == value)
            return;
          this.radianNormalWidth = value;
        }
      }

      private int radianMaxWidth;
      /// <summary>
      /// 圆弧最大宽度
      /// </summary>
      [Browsable(false)]
      [Description("圆弧最大宽度")]
      public int RadianMaxWidth
      {
        get { return this.radianMaxWidth; }
        set
        {
          if (this.radianMaxWidth == value)
            return;
          this.radianMaxWidth = value;
        }
      }

      private int radianNowWidth;
      /// <summary>
      /// 当前圆弧宽度
      /// </summary>
      [Browsable(false)]
      [Description("当前圆弧宽度")]
      public int RadianNowWidth
      {
        get { return this.radianNowWidth; }
        set
        {
          if (this.radianNowWidth == value)
            return;
          this.radianNowWidth = value;
        }
      }
    }

    /// <summary>
    /// 圆弧选项鼠标状态
    /// </summary>
    [Description("圆弧选项鼠标状态")]
    public enum MoveState
    {
      /// <summary>
      /// 光标已离开可视区
      /// </summary>
      Leave,
      /// <summary>
      /// 光标已离开可视区(动画还在进行中)
      /// </summary>
      LeaveAnimation,
      /// <summary>
      /// 光标已进入可视区
      /// </summary>
      Enter,
      /// <summary>
      /// 光标已进入可视区(动画还在进行中)
      /// </summary>
      EnterAnimation
    }

  }

  /// <summary>
  /// 圆弧选项单击事件参数
  /// </summary>
  [Description("鱼眼菜单单击事件参数")]
  public class RadianMenuItemEventArgs : EventArgs
  {
    /// <summary>
    /// 鱼眼菜单选项
    /// </summary>
    [Description("鱼眼菜单选项")]
    public RadianMenuExt.RadianMenuItem Item { get; set; }
  }

源码下载:GDI不规则圆弧菜单控件.zip

GDI不规则圆弧菜单控件----------WinForm控件开发系列

上一篇:Visual Studio Tools for Office: Using C# with Excel, Word, Outlook, and InfoPath【15】


下一篇:(三十三)c#Winform自定义控件-日期控件