Don Kirkby
Don Kirkby

Reputation: 56660

Restoring SplitterDistance inside TabControl is inconsistent

I'm writing a WinForms application and one of the tabs in my TabControl has a SplitContainer. I'm saving the SplitterDistance in the user's application settings, but the restore is inconsistent. If the tab page with the splitter is visible, then the restore works and the splitter distance is as I left it. If some other tab is selected, then the splitter distance is wrong.

Upvotes: 10

Views: 8281

Answers (9)

Steve Ostlind
Steve Ostlind

Reputation: 21

Save the splitter distance as a percentage of the split container height. Then restore the splitter distance percentage using the current split container height.

  /// <summary>
  /// Gets or sets the relative size of the top and bottom split window panes.
  /// </summary>
  [Browsable(false)]
  [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  [UserScopedSetting]
  [DefaultSettingValue(".5")]
  public double SplitterDistancePercent
  {
     get { return (double)toplevelSplitContainer.SplitterDistance / toplevelSplitContainer.Size.Height; }
     set { toplevelSplitContainer.SplitterDistance = (int)((double)toplevelSplitContainer.Size.Height * value); }
  }

Upvotes: 2

Michael Ross
Michael Ross

Reputation: 570

Set the containing TabPage.Width = TabControl.Width - 8 before setting the SplitContainer.SplitDistance

Upvotes: 0

Andark
Andark

Reputation: 410

As it was mentioned, control with SplitContainer doesn't get resized to match the tab control until it gets selected. If you handle restoring by setting SplitterDistance in percentage (storedDistance * fullDistance / 100) in case of FixedPanel.None, you will see the splitter moving in some time because of precision of calculations.

I found another solution for this problem. I subscribes to one of the events, for example Paint event. This event comes after control’s resizing, so the SplitContainer will have correct value. After first restoring you should unsubscribe from this event in order to restore only once:

private void MainForm_Load(object sender, EventArgs e)
{
    splitContainerControl.Paint += new PaintEventHandler(splitContainerControl_Paint);
}

void splitContainerControl_Paint(object sender, PaintEventArgs e)
{
    splitContainerControl.Paint -= splitContainerControl_Paint;
    // Handle restoration here
}

Upvotes: 5

hrbek
hrbek

Reputation: 1

Answer is time synchrinizations. You must set SplitterDistance when window is done with size changing. You must then flag for final resize and then set SplitterDistance. In this case is all right

Upvotes: 0

CristisS
CristisS

Reputation: 1163

I had the same problem. In my particular case, I was using forms, that I transformed into tabpages and added to the tab control. The solution I found, was to set the splitter distances in the Form_Shown event, not in the load event.

Upvotes: 3

DelftRed
DelftRed

Reputation: 316

Restoring splitter distances has given me a lot of grief too. I have found that restoring them from my user settings in the form (or user control) Load event gave much better results than using the constructor. Trying to do it in the constructor gave me all sorts of weird behaviour.

Upvotes: 0

Robert Jeppesen
Robert Jeppesen

Reputation: 7877

For handling all cases of FixedPanel and orientation, something like the following should work:

        var fullDistance = 
           new Func<SplitContainer, int>(
               c => c.Orientation == 
                  Orientation.Horizontal ? c.Size.Height : c.Size.Width);

        // Store as percentage if FixedPanel.None
        int distanceToStore =
           spl.FixedPanel == FixedPanel.Panel1 ? spl.SplitterDistance :
           spl.FixedPanel == FixedPanel.Panel2 ? fullDistance(spl) - spl.SplitterDistance :
           (int)(((double)spl.SplitterDistance) / ((double)fullDistance(spl))) * 100;

Then do the same when restoring

        // calculate splitter distance with regard to current control size
        int distanceToRestore =
           spl.FixedPanel == FixedPanel.Panel1 ? storedDistance:
           spl.FixedPanel == FixedPanel.Panel2 ? fullDistance(spl) - storedDistance :
           storedDistance * fullDistance(spl) / 100;

Upvotes: 4

R Lange
R Lange

Reputation:

There`s a more easy solution. If Panel1 is set as the fixed panel in SplitContainer.FixedPanel property it all behaves as expected.

Upvotes: 18

Don Kirkby
Don Kirkby

Reputation: 56660

I found the problem. Each tab page doesn't get resized to match the tab control until it gets selected. For example, if the tab control is 100 pixels wide in the designer, and you've just set it to 500 pixels during load, then setting the splitter distance to 50 on a hidden tab page will get resized to a splitter distance of 250 when you select that tab page.

I worked around it by recording the SplitterDistance and Width properties of the SplitContainer in my application settings. Then on restore I set the SplitterDistance to recordedSplitterDistance * Width / recordedWidth.

Upvotes: 7

Related Questions