开发者

Making splitter visible for Split Panel

How do I make a split panels splitter visible to开发者_高级运维 the user, rather than being invisible with only a cursor change on mouse over?


This question arises because the SplitContainer control has no direct property for setting the style of the draggable splitter bar itself.

There are several ways to accomplish this, and even though the other answers posted here work, the one that I share with you below is ultimately the fast, reliable and easiest way.

@BluMonkMN suggested a method using a 3D border, but what if you don't want any border?

@Giles Bathgate suggested adding a Paint event handler that, even though it surely is elegant and does work, comes with a slight performance cost requiring you to add more code to your project that executes at the C# level and may someday become a maintenance issue.

@Philip Fourie suggested changing the SplitContainer.BackColor property value; however, that initially causes the control's entire background to change color, not just the splitter bar, causing no color contrast.

So, my solution is an enhancement of @Philip Fourie's.

First, I'll mention that the SplitContainer actually has two distinct sub-containers, both separated by the splitter bar. These two are represented by the Panel1 and the Panel2 properties. Each of them is essentially a Panel container with their own BackColor properties, in addition to several other properties.

The SplitContainer has its own BackColor property, making a total of three unique possible colors.

Now, if you were to set this SplitContainer.BackColor property, the Panel1 and Panel2 "subcontrols" would automatically inherit that color value, and now they'd all be the same, causing NO visual contrast!
This [probably undesirable] property value inheritance only happens when the Panel1.BackColor and/or the Panel2.BackColor properties have not yet been explicitly set by you (even though viewing their property values in the Visual Studio Properties window ahead of time would have revealed "Control.")

Therefore, the order that you set the properties is important:

  1. Set both the "child" Panel1.BackColor and Panel2.BackColor properties to something other than the default value of "Control" to force an explicit value (even if you really do want "Control"; we'll fix that later.)
  2. Set the "parent" SplitContainer.BackColor to the color you desire the splitter bar to be.
  3. Finally, go back and set the Panel1.BackColor and Panel2.BackColor properties to the color you want them to be (perhaps back to "Control".)

And as @Philip Fourie answered, you may wish to set the Width property, actually consistently named SplitterWidth, regardless of the [Horizontal vs. Vertical] Orientation property.

Here are some useful tips:

While working in the Visual Studio form designer, if you click on the SplitContainer on either side of the splitter bar, you'll select that Panel1 or Panel2 "child" sub-container. But if you click on the splitter bar itself, you'll select the "parent" SplitContainer.

And related to what @Stuart Helwig suggested, the default SplitterWidth will cause the splitter bar to be outlined when it has focus, thus obscuring the color you selected. Raise the value to 5, 6, or higher, which also makes it easier for the end-user to grab & drag.

Finished. Happy Coding!


Try setting BorderStyle to Fixed3D


You could paint your own splitter bar by adding the following event handler to the splitcontainer paint event.

private void SplitterPaint(object sender, PaintEventArgs e)
{
    SplitContainer s = sender as SplitContainer;
    if (s != null) {
        int top = 5;
        int bottom = s.Height - 5;
        int left = s.SplitterDistance;
        int right = left + s.SplitterWidth - 1;
        e.Graphics.DrawLine(Pens.Silver, left, top, left, bottom);
        e.Graphics.DrawLine(Pens.Silver, right, top, right, bottom);
    }
}


You can use SplitterColor in designer to change splitter border color.

public class SplitContainerCustomSplitter : SplitContainer
{
    [DefaultValue(typeof(Color), "Black")]
    public Color SplitterColor { get; set; } = Color.Black;

    protected override void OnPaint(PaintEventArgs pevent)
    {
        Graphics g = pevent.Graphics;
        Rectangle rect = SplitterRectangle;

        using (Pen pen = new Pen(SplitterColor))
        {
            if (Orientation == Orientation.Vertical)
            {
                g.DrawLine(pen, rect.Left, rect.Top, rect.Left, rect.Bottom - 1);
                g.DrawLine(pen, rect.Right - 1, rect.Top, rect.Right - 1, rect.Bottom - 1);
            }
            else
            {
                g.DrawLine(pen, rect.Left, rect.Top, rect.Right - 1, rect.Top);
                g.DrawLine(pen, rect.Left, rect.Bottom - 1, rect.Right, rect.Bottom - 1);
            }
        }
    }
}


One way would be to change the Splitter's BackColor and Width/Height properties (depending on the splitter's orientation)


Improved variant of Giles Bathgate's answer:

private void ds_SplitContainer_Paint(object sender, PaintEventArgs e)
{
    SplitContainer l_SplitContainer = sender as SplitContainer;

    if (l_SplitContainer != null)
    {
        Rectangle ll_ShrinkedSplitterRectangle = l_SplitContainer.SplitterRectangle;
        ll_ShrinkedSplitterRectangle.Offset(0, 2);
        ll_ShrinkedSplitterRectangle.Height = ll_ShrinkedSplitterRectangle.Height - 2;
        e.Graphics.FillRectangle(Brushes.Silver, ll_ShrinkedSplitterRectangle);
    }
}


Here is a quick implementation of a horizontal splitter that is filled with a color, has a top and bottom border (similar to Visual Studio splitters), and gripper dots in the middle.

    private void splitContainer_Paint(object sender, PaintEventArgs e)
    {
        SplitContainer s = sender as SplitContainer;
        if (s != null)
        {
            int gripLineWidth = 9;
            // Fill Splitter rectangle
            e.Graphics.FillRectangle(SystemBrushes.ControlDark, 
                s.SplitterRectangle.X, s.SplitterDistance, s.SplitterRectangle.Width, s.SplitterWidth);
            // Draw Single Line Border on Top and Bottom
            e.Graphics.DrawLine(Pens.LightSlateGray,
                s.SplitterRectangle.X, s.SplitterDistance, s.SplitterRectangle.Width, s.SplitterDistance);
            e.Graphics.DrawLine(Pens.LightSlateGray,
                s.SplitterRectangle.X, s.SplitterDistance + s.SplitterWidth - 1, s.SplitterRectangle.Width, s.SplitterDistance + s.SplitterWidth - 1);
            // Draw gripper dots in center
            e.Graphics.DrawLine(_dashedPen,
                ((s.SplitterRectangle.Width / 2) - (gripLineWidth / 2)),
                s.SplitterDistance + s.SplitterWidth / 2,
                ((s.SplitterRectangle.Width / 2) + (gripLineWidth / 2)),
                s.SplitterDistance + s.SplitterWidth / 2);
        }
    }

You can create a Pen as a member variable in the class that performs the drawing which will draw a dotted line in your similar to:

private static Pen _dashedPen = new Pen(Color.DarkRed, 1);
_dashedPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;


As well as making its BorderStyle Fixed3D as @BlueMonkMN suggested I often find the default SplitterWidth value on the splitContainer object, of 4, is a little narrow.

If you up that to about 6, with a 3D border, it's a little more obvious to the user.


Set the BackColor property of the SplitContainer to different color. Let say Black. Then each SpliterPanel, change its BackColor property to different color. Let say White. Then you will notice the SplitLine will become more visible. :)


After trying a few of the methods suggested here and not amusing me, I decided to put in a panel1 and in panel2 a thin labels, aligned to the splitter and everything is ok.

(label's.Autosize=false, label's.Text = "", label's.Color=SystemColor.Selected,  label1.Dock=left; label2.Dock=right)


This is an improvement to GlobalSoftwareSociety's great answer.

To prevent the panels from inheriting the BackColor, it is only needed to write to the property once. You can in fact simply assign the property to itself. This also works for other kinds of controls and similarly inherited properties, like fonts.

Also, to avoid the annoying selection rectangle, make the SplitContainer not a tabstop, and activate the first panel on mouse up.

(Need to be careful; at first I tried putting a "tab to next control" call in the Enter event, but that prevented all sub controls from ever being activated.)

All together, this makes the fix look something like:

splitBox.Panel1.BackColor = splitBox.Panel1.BackColor;
splitBox.Panel2.BackColor = splitBox.Panel2.BackColor;
splitBox.BackColor = yourFavouriteColor;
splitBox.SplitterWidth = yourFavouriteSize;
splitBox.TabStop = false;
splitBox.MouseUp += (s, e) => splitBox.ActiveControl = splitBox.Panel1;


The splitter line is visible actually. The real question is it is hard to distinct with other controls.

One idea is to set a new background color to the split container, and make it different with its child panels.

Maybe sometimes we could solve the issue from designer's perspective, not developer's. :-)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜