Inspired by the layout of Lotus Notes, I designed something that I think would be useful in this situation. It only contains one button between the panels which toggles expand/collapse state of a single panel but can easily be modified to use two buttons to control both the right and left panels. It uses two split containers, one docked inside the other, and the mouseMove event of the “middle” panel to simulate dragging a splitter (Moving a control by dragging it with the mouse in C#).
Additionally, I use the ClientSizedChanged event of the containers to handle the logic of toggling button images instead of the method which collapses/expands the panel (Detect when SplitContainer collapsed changes).
Design:
splitContainer1
╔════════════╤═════════════════════════════════╗
║ │ splitContainer2 (docked fill) ║
║ │ ╔════════════╤════════════════╗ ║
║ │ ║ │ ║ ║
║ │ ║ Button(s) │ ║ ║
║ │ ║ [<>] │ ║ ║
║ │ ║ │ ║ ║
║ │ ╚════════════╧════════════════╝ ║
╚════════════╧═════════════════════════════════╝
splitContainer2.Dock = DockStyle.Fill;
splitContainer1 = splitContainer2.IsSplitterFixed = true;
splitContainer2.Panel1.Cursor = Cursors.VSplit;
Anchor button left or right(or dock several buttons inside an tableLayout control) . Just make sure there is still some part of the panel available to click/drag on.
Set the maximum with of the middle panel to a low number. Size depends on how wide you need your buttons to be.
Code:
Panel will switch to opposite state
If you really need one button with two parts instead of two buttons or a toggle button you would need to get the mouse coordinates clicked and have differnt logic depending on where the click occured.
private void btnExpand_Click(object sender, EventArgs e)
{
splitContainer1.Panel1Collapsed = !splitContainer1.Panel1Collapsed;
}
Handel logic associated with the expand/collapse. I chose to use this event because there are several ways in my program the user can collapse/expand panels.
private void splitContainer1_Panel2_ClientSizeChanged(object sender, EventArgs e)
{
if (splitContainer1.Panel1Collapsed)
{
splitContainer2.Panel1.Cursor = Cursors.Default;
this.btnExpand.Image = imageExpand;
}
Else
{
splitContainer2.Panel1.Cursor = Cursors.VSplit;
this.btnExpand.Image = imageCollapse;
}
}
Handel the resizing of the panels due to moving the faux splitter
private void splitContainer2_Panel1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
/* All you really need is this:
splitContainer1.SplitterDistance += e.X;
Note: Splitter distance must be a positive integer and e.X will be negitive when dragging to the left of the splitContainer. You could handel this check here or on the splitterMoving event.
The code I have below shows how to “snap” a panel closed if the splitter is moved close enough to the edge
Or prevent a panel from being hidden from view (which could also be accomplished by setting the minimum size of a panel).
*/
if (e.X + splitContainer1.SplitterDistance < 40)
{
while (splitContainer1.SplitterDistance > 1)
splitContainer1.SplitterDistance--;
splitContainer1.Panel1Collapsed = true;
}
else if ((e.X + splitContainer1.SplitterDistance) * 1.00 / this.Width * 1.00 < .75)
splitContainer1.SplitterDistance += e.X;
else
Cursor.Current = Cursors.No;
}
}