C# TabControl填充会导致TabPage中的隐藏控件错误地重新排序

C# TabControl填充会导致TabPage中的隐藏控件错误地重新排序,c#,winforms,tabcontrol,C#,Winforms,Tabcontrol,当选项卡Control的Padding属性更改时,尚未创建句柄的控件似乎被推到其父控件的底部。查看.NET源代码,Padding调用重新创建句柄(),似乎与此有关 下面是说明问题的代码。每个复选框的下方都有相应的标签。有些标签在开始时可见,有些则隐藏。选中person0复选框会使person0标签出现,但底部显示不正确。相反,person0标签应该显示在person0复选框的正下方,这是它添加到FlowLayoutPanel的顺序。见截图 该代码提供了一个booldoworkaround选项,但

选项卡Control
Padding
属性更改时,尚未创建
句柄的控件似乎被推到其父控件
的底部。查看
.NET
源代码,
Padding
调用
重新创建句柄(),似乎与此有关

下面是说明问题的代码。每个
复选框
的下方都有相应的
标签
。有些标签在开始时可见,有些则隐藏。选中
person0
复选框会使
person0
标签出现,但底部显示不正确。相反,person0标签应该显示在person0复选框的正下方,这是它添加到
FlowLayoutPanel
的顺序。见截图

该代码提供了一个
booldoworkaround
选项,但必须有更好的方法。强制使用
CreateControl()
创建所有
句柄
,似乎也不正确

使用系统;
使用System.Collections.Generic;
使用系统图;
使用System.Linq;
使用System.Windows.Forms;
命名空间Windows窗体应用程序3{
公共类TabControl3:TabControl{
private bool doWorkaround=false;//设置为true以防止错误
受保护的覆盖无效OnFontChanged(事件参数e){
基数(e);
int h=(int)this.Font.Height;
SetPadding(新点(h,h));//调用此函数会导致控件重新排序错误
}
///设置填充将导致TabControl重新创建所有句柄,这将导致隐藏的无把手控件重新排列。
公共虚拟无效设置填充(点pt){
//解决方案:从选项卡页中删除所有控件,然后在完成后将其添加回。
int n=TabPages.Count;
控件[][]arr=null;
如果(doWorkaround){
arr=新控件[n][];
对于(int i=0;i

我使用
.NET 3.5,4,4.52进行了测试,发现这三个版本的行为都相同。

覆盖选项卡控件的
OnControlAdded
,并添加
base.OnControlAdded(e);如果(e.Control是TabPage){e.Control.Controls.OfType().ToList().ForEach(c=>c.CreateControl());}
。另外,在
OnFontChanged
(您也可以使用
OnLayout
)中,在
base()
之后添加
,如果(!this.IsHandleCreated)返回。删除
SetPadding()
中的所有内容,除了
this.Padding=ptvar p=new Point(Font.Height,Font.Height),OnFontChanged中的code>可能会更好;如果(!Padding.Equals(p))设置Padding(p)顺便说一句,您可以使用TableLayoutPanel而不是FlowLayoutPanel:)(或者一个用户控件而不是两个控件)覆盖TabControl的
OnControlAdded
,并添加
base.OnControlAdded(e);如果(e.Control是TabPage){e.Control.Controls.OfType().ToList().ForEach(c=>c.CreateControl());}
。另外,在
OnFontChanged
(您也可以使用
OnLayout
)中,在
base()
之后添加
,如果(!this.IsHandleCreated)返回。删除
SetPadding()
中的所有内容,除了
this.Padding=ptvar p=new Point(Font.Height,Font.Height),OnFontChanged中的code>可能会更好;如果(!Padding.Equals(p))设置Padding(p)顺便说一句,您可以使用TableLayoutPanel来代替
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;

namespace WindowsFormsApplication3 {

public class TabControl3 : TabControl {

    private bool doWorkaround = false; // set to true to prevent the bug

    protected override void OnFontChanged(EventArgs e) {
        base.OnFontChanged(e);
        int h = (int) this.Font.Height;
        SetPadding(new Point(h, h)); // calling this causes the Controls to re-order incorrectly
    }

    ///<summary>Setting the padding causes the TabControl to recreate all the handles, which causes the hidden handleless controls to rearrange.</summary>
    public virtual void SetPadding(Point pt) {
        // Workaround solution: remove all controls from tab pages and then add them back after.
        int n = TabPages.Count;
        Control[][] arr = null;
        if (doWorkaround) {
            arr = new Control[n][];
            for (int i = 0; i < n; i++) {
                TabPage tp = TabPages[i];
                arr[i] = tp.Controls.Cast<Control>().ToArray();
                tp.Controls.Clear();
            }
        }

        this.Padding = pt; // in the .NET source code, setting Padding calls RecreateHandle()

        if (doWorkaround) {
            for (int i = 0; i < n; i++)
                TabPages[i].Controls.AddRange(arr[i]);
        }
    }
}

public class CheckBox2 : CheckBox {
    public CheckBox2(String text, bool isChecked = false) : base() {
        this.Text = text;
        this.AutoSize = true;
        this.Checked = isChecked;
    }
}

public class Label2 : Label {
    public Label2(String text) : base() {
        this.Text = text;
        this.AutoSize = true;
    }
}

public class MyForm : Form {

    TabControl tc = new TabControl3 { Dock = DockStyle.Fill };

    public MyForm() {
        this.Size = new System.Drawing.Size(600, 800);
        this.StartPosition = FormStartPosition.CenterScreen;
        TabPage tp1 = new TabPage("Page1");

        FlowLayoutPanel p = new FlowLayoutPanel { FlowDirection = System.Windows.Forms.FlowDirection.TopDown, Dock = DockStyle.Fill };

        p.Controls.Add(new CheckBox2("Person0"));
        p.Controls.Add(new Label2("Person0") { Visible = false });

        p.Controls.Add(new CheckBox2("Person1", true));
        p.Controls.Add(new Label2("Person1"));

        p.Controls.Add(new CheckBox2("Person2", true));
        p.Controls.Add(new Label2("Person2"));

        p.Controls.Add(new CheckBox2("Person3"));
        p.Controls.Add(new Label2("Person3") { Visible = false });

        p.Controls.Add(new CheckBox2("Person4"));
        p.Controls.Add(new Label2("Person4") { Visible = false });

        for (int i = 0; i < p.Controls.Count; i += 2) {
            CheckBox cb = (CheckBox) p.Controls[i];
            Label lb = (Label) p.Controls[i+1];
            cb.CheckedChanged += delegate {
                bool b = cb.Checked;
                lb.Visible = b;
            };
        }

        tp1.Controls.Add(p);
        tc.TabPages.Add(tp1);

        Controls.Add(tc);
    }

    protected override void OnLoad(EventArgs e) {
        base.OnLoad(e);
        this.Font = SystemFonts.MenuFont; // to trigger the bug
    }
}

static class Program {
    [STAThread]
    static void Main() {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new MyForm());
    }
}
}