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:
- Set both the "child"
Panel1.BackColor
andPanel2.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.) - Set the "parent"
SplitContainer.BackColor
to the color you desire the splitter bar to be. - Finally, go back and set the
Panel1.BackColor
andPanel2.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. :-)
精彩评论