C# 恢复TabControl内的SplitterDistance不一致

C# 恢复TabControl内的SplitterDistance不一致,c#,.net,winforms,C#,.net,Winforms,我正在编写一个WinForms应用程序,TabControl中的一个选项卡有一个SplitContainer。我正在用户的应用程序设置中保存SplitterDistance,但还原不一致。如果带有拆分器的选项卡页面可见,则恢复工作正常,拆分器的距离与我离开时的距离相同。如果选择了其他选项卡,则拆分器距离错误。我发现了问题。在选中每个选项卡页之前,不会调整其大小以匹配选项卡控件。例如,如果在设计器中选项卡控件的宽度为100像素,而您在加载期间刚刚将其设置为500像素,则在隐藏选项卡页面上将拆分器距

我正在编写一个WinForms应用程序,TabControl中的一个选项卡有一个SplitContainer。我正在用户的应用程序设置中保存SplitterDistance,但还原不一致。如果带有拆分器的选项卡页面可见,则恢复工作正常,拆分器的距离与我离开时的距离相同。如果选择了其他选项卡,则拆分器距离错误。

我发现了问题。在选中每个选项卡页之前,不会调整其大小以匹配选项卡控件。例如,如果在设计器中选项卡控件的宽度为100像素,而您在加载期间刚刚将其设置为500像素,则在隐藏选项卡页面上将拆分器距离设置为50,则当您选择该选项卡页面时,拆分器距离将调整为250


我通过在应用程序设置中记录SplitterDistance和SplitContainer的宽度属性来解决这个问题。然后在恢复时,我将SplitterDistance设置为recordedSplitterDistance*Width/recordedWidth。

有一个更简单的解决方案。如果Panel1被设置为SplitContainer.FixedPanel属性中的固定面板,则其行为与预期一致。

对于处理所有固定面板和方向的情况,应采用以下类似方法:

        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;

恢复分裂距离也给了我很多悲伤。我发现从表单(或用户控件)加载事件中的用户设置中恢复它们比使用构造函数得到更好的结果。在构造器中尝试这样做会给我带来各种奇怪的行为。

我也有同样的问题。在我的特殊情况下,我使用表单,将表单转换为tabpages并添加到tab控件中。
我找到的解决方案是在Form_Showed事件中设置拆分器距离,而不是在load事件中设置拆分器距离。

答案是时间同步。当窗口完成大小更改时,必须设置SplitterDistance。然后必须标记最终调整大小,然后设置SplitterDistance。在这种情况下,正如前面提到的,带有SplitContainer的控件在被选中之前不会调整大小以匹配选项卡控件。如果在FixedPanel.None的情况下通过设置SplitterDistance(以百分比表示)(storedDistance*fullDistance/100)来处理恢复,则由于计算精度的原因,您将在一段时间内看到拆分器移动

我找到了解决这个问题的另一个办法。我订阅了其中一个事件,例如绘画事件。此事件发生在控件调整大小之后,因此SplitContainer将具有正确的值。首次恢复后,您应取消订阅此事件,以便仅恢复一次:

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
}

在设置拆分容器之前,先设置包含选项卡Page.Width=TabControl.Width-8。拆分距离将拆分器距离保存为拆分容器高度的百分比。然后使用当前拆分容器高度恢复拆分器距离百分比

  /// <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); }
  }
//
///获取或设置顶部和底部拆分窗口窗格的相对大小。
/// 
[可浏览(错误)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[用户范围设置]
[默认设置值(“.5”)]
公共双拆分器距离百分比
{
获取{return(double)toplevelSplitContainer.SplitterDistance/toplevelSplitContainer.Size.Height;}
设置{toplevelSplitContainer.SplitterDistance=(int)((double)toplevelSplitContainer.Size.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); }
  }