Search code examples
.netwinforms.net-2.0splitcontainer

Add button control(s) to SplitContainer Splitter


Is there any way to display controls (like buttons) on the adjustable splitter that displays between the two panels in a .NET SplitContainer?

Example:

Diagram

I don't think SplitContainer natively supports this, but overriding the control to get this functionality that seems omni-present in numerous applications seems a bit much to me - I feel like I'm over-thinking this or missing something obvious.


Solution

  • Here's an example that uses a TableLayoutPanel to simulate a SplitContainer.

    using System;
    using System.Diagnostics;
    using System.Drawing;
    using System.Windows.Forms;
    
    class Form1 : Form
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    
        TableLayoutPanel rootPanel;
        float originalWidth;
        int splitPointX;
    
        public Form1()
        {
            Controls.Add(rootPanel = new TableLayoutPanel
            {
                ColumnCount = 3,
                ColumnStyles =
                {
                    // Notice the use of Absolute here as this will control the 'splitting'
                    new ColumnStyle(SizeType.Absolute, 120F),
                    // Size of button panel
                    new ColumnStyle(SizeType.AutoSize),
                    // Remaining size
                    new ColumnStyle(SizeType.Percent, 100F),
                },
                Dock = DockStyle.Fill,
                RowCount = 1,
                RowStyles = { new RowStyle(SizeType.Percent, 100F) },
            });
    
            Panel buttonPanel;
            rootPanel.Controls.Add(buttonPanel = new Panel
            {
                Anchor = AnchorStyles.Top | AnchorStyles.Bottom,
                BackColor = SystemColors.ControlDark,
                Margin = new Padding(0),
                MinimumSize = new Size(80, 0),
                Size = new Size(80, 0),
                Controls =
                {
                    // UseVisualStyleBackColor = true only because we altered the container's BackColor
                    new Button { Text = ">>", Location = new Point(19, 112), Size = new Size(40, 23), UseVisualStyleBackColor = true },
                    new Button { Text = ">", Location = new Point(19, 83), Size = new Size(40, 23), UseVisualStyleBackColor = true },
                    new Button { Text = "<", Location = new Point(19, 54), Size = new Size(40, 23), UseVisualStyleBackColor = true },
                    new Button { Text = "<<", Location = new Point(19, 25), Size = new Size(40, 23), UseVisualStyleBackColor = true },
                },
            }, 1, 0);
    
            buttonPanel.MouseDown += (s, e) =>
                {
                    if (e.Button == MouseButtons.Left)
                    {
                        // Capture mouse so that all mouse move messages go to this control
                        (s as Control).Capture = true;
    
                        // Record original column width
                        originalWidth = rootPanel.ColumnStyles[0].Width;
    
                        // Record first clicked point
                        // Convert to screen coordinates because this window will be a moving target
                        Point windowPoint = (s as Control).PointToScreen(e.Location);
                        splitPointX = windowPoint.X;
                    }
                };
            buttonPanel.MouseMove += (s, e) =>
                {
                    if ((s as Control).Capture)
                    {
                        Point windowPoint = (s as Control).PointToScreen(e.Location);
    
                        // Calculate distance of mouse from splitPoint
                        int offset = windowPoint.X - splitPointX;
    
                        // Apply to originalWidth
                        float newWidth = originalWidth + offset;
    
                        // Clamp it.
                        // The control in the left pane's MinimumSize.Width would be more appropriate than zero
                        newWidth = Math.Max(0, newWidth);
    
                        // Update column width
                        if (Math.Abs(newWidth - rootPanel.ColumnStyles[0].Width) >= 1)
                            rootPanel.ColumnStyles[0].Width = newWidth;
                    }
                };
            buttonPanel.MouseUp += (s, e) =>
                {
                    if (e.Button == MouseButtons.Left)
                    {
                        // Release mouse capture
                        if ((s as Control).Capture)
                            (s as Control).Capture = false;
                    }
                };
        }
    }