Saltar al contenido

Botón Windows.Forms con menú desplegable

Nuestro grupo de redactores ha estado mucho tiempo investigando la resolución a tu búsqueda, te compartimos la soluciones de modo que esperamos serte de gran ayuda.

Solución:

El botón tiene una flecha hacia abajo en el lado derecho y puede configurar el menú desde el diseñador:

ss

Con ShowMenuUnderCursor:

ss

Clase de botón de menú:

public class MenuButton : Button

    [DefaultValue(null)]
    public ContextMenuStrip Menu  get; set; 

    [DefaultValue(false)]
    public bool ShowMenuUnderCursor  get; set; 

    protected override void OnMouseDown(MouseEventArgs mevent)
    
        base.OnMouseDown(mevent);

        if (Menu != null && mevent.Button == MouseButtons.Left)
        
            Point menuLocation;

            if (ShowMenuUnderCursor)
            
                menuLocation = mevent.Location;
            
            else
            
                menuLocation = new Point(0, Height);
            

            Menu.Show(this, menuLocation);
        
    

    protected override void OnPaint(PaintEventArgs pevent)
    
        base.OnPaint(pevent);

        if (Menu != null)
        
            int arrowX = ClientRectangle.Width - 14;
            int arrowY = ClientRectangle.Height / 2 - 1;

            Brush brush = Enabled ? SystemBrushes.ControlText : SystemBrushes.ControlDark;
            Point[] arrows = new Point[]  new Point(arrowX, arrowY), new Point(arrowX + 7, arrowY), new Point(arrowX + 3, arrowY + 4) ;
            pevent.Graphics.FillPolygon(brush, arrows);
        
    

Puede mostrar ContextMenuStrip en el evento de clic:

private void button1_Click(object sender, EventArgs e) 
  contextMenuStrip1.Show(button1, new Point(0, button1.Height));

Para tomar su propia decisión de mostrar el menú encima o debajo del botón, puede intentar usar este código, que mide el menú y determina si estará parcialmente fuera de la pantalla o no:

private void button1_Click(object sender, EventArgs e) 
  Point screenPoint = button1.PointToScreen(new Point(button1.Left, button1.Bottom));
  if (screenPoint.Y + contextMenuStrip1.Size.Height > Screen.PrimaryScreen.WorkingArea.Height) 
    contextMenuStrip1.Show(button1, new Point(0, -contextMenuStrip1.Size.Height));
   else 
    contextMenuStrip1.Show(button1, new Point(0, button1.Height));
      

Expandiendo un poco la respuesta de @Jaex para permitir una línea de separación, dibujo condicional de la flecha si no hay nada configurado y un evento de clic separado para el cuerpo del botón principal y la flecha del menú.

Cabe señalar que para una mejor alineación se puede configurar el button.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;

ingrese la descripción de la imagen aquí

Aquí está mi ligera mejora.

public class SplitButton : Button

    [DefaultValue(null), Browsable(true),
    DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public ContextMenuStrip Menu  get; set; 

    [DefaultValue(20), Browsable(true),
    DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public int SplitWidth  get; set; 

    public SplitButton() 
    
        SplitWidth = 20;
    

    protected override void OnMouseDown(MouseEventArgs mevent)
    
        var splitRect = new Rectangle(this.Width - this.SplitWidth, 0, this.SplitWidth, this.Height);

        // Figure out if the button click was on the button itself or the menu split
        if (Menu != null && 
            mevent.Button == MouseButtons.Left &&
            splitRect.Contains(mevent.Location) )
        
            Menu.Show(this, 0, this.Height);    // Shows menu under button
            //Menu.Show(this, mevent.Location); // Shows menu at click location
        
        else
        
            base.OnMouseDown(mevent);
        
    

    protected override void OnPaint(PaintEventArgs pevent)
    
        base.OnPaint(pevent);

        if (this.Menu != null && this.SplitWidth > 0)
         
            // Draw the arrow glyph on the right side of the button
            int arrowX = ClientRectangle.Width - 14;
            int arrowY = ClientRectangle.Height / 2 - 1;

            var arrowBrush = Enabled ? SystemBrushes.ControlText : SystemBrushes.ButtonShadow;
            var arrows = new[]  new Point(arrowX, arrowY), new Point(arrowX + 7, arrowY), new Point(arrowX + 3, arrowY + 4) ;
            pevent.Graphics.FillPolygon(arrowBrush, arrows);

            // Draw a dashed separator on the left of the arrow
            int lineX = ClientRectangle.Width - this.SplitWidth;
            int lineYFrom = arrowY - 4;
            int lineYTo = arrowY + 8;
            using( var separatorPen = new Pen(Brushes.DarkGray)DashStyle = DashStyle.Dot)
            
                pevent.Graphics.DrawLine(separatorPen, lineX, lineYFrom, lineX, lineYTo);
            
        
    

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *