Introduction
When a SplitterContainer
control with a fixed panel is resized due to the DPI setting, the SplitterDistance
value is not changed. This may result in the fixed panel appearing either too small or too large, depending on whether the DPI setting was increased or decreased.
For example, a Form with AutoScaleMode
set to ScaleMode.DPI
, and a SplitterContainer
with FixedPanel
set to Panel1
and SplitterDistance
set to 140 appears as follows at it's native DPI (100%):
This is how it appears when run at a higher DPI (125%):
All the controls were resized, but SplitterDistance
was left unchanged at 140.
Note that this is only a problem when SplitterContainer.FixedPanel
is set to Panel1
or Panel2
. If it was set to None
, then SplitterDistance
would be adjusted to match the resizing.
The solution to adjust SplitterDistance
during the Form.Shown
event handler. The resizing does not work properly if performed in the constructor or the Form.Load
event handler.
Using the code
Include the following code snippet in your Form-derived class:
private SizeF scale = new SizeF(1.0f, 1.0f);
protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
{
scale = new SizeF(scale.Width * factor.Width, scale.Height * factor.Height);
base.ScaleControl(factor, specified);
}
private void Fix(Control c)
{
foreach (Control child in c.Controls)
{
if (child is SplitContainer)
{
SplitContainer sp = (SplitContainer)child;
Fix(sp);
Fix(sp.Panel1);
Fix(sp.Panel2);
}
else
{
Fix(child);
}
}
}
private void Fix(SplitContainer sp)
{
float sc = (sp.Orientation == Orientation.Vertical) ? scale.Width : scale.Height;
if (sp.FixedPanel == FixedPanel.Panel1)
{
sp.SplitterDistance = (int)Math.Round((float)sp.SplitterDistance * sc);
}
else if (sp.FixedPanel == FixedPanel.Panel2)
{
int cs = (sp.Orientation == Orientation.Vertical) ? sp.Panel2.ClientSize.Width :sp.Panel2.ClientSize.Height;
int newcs = (int)((float)cs * sc);
sp.SplitterDistance -= (newcs - cs);
}
}
Remember to call Fix(this)
from the Form's Shown
event handler. For Example:
private void Form1_Shown(object sender, EventArgs e)
{
Fix(this);
}
Points of Interest
I am puzzled as to why the SplitterDistance values must be adjusted during the <code>Form.Shown
event handler, and not during Form.Load
or the constructor. If anyone can explain this, please leave a comment.
History
- June 14, 2014 - First release.