简体   繁体   English

选择选项卡时,TabControl 重新排序 ControlCollection

[英]TabControl reordering ControlCollection when selecting a tab

Alright, I have a weird one here again.好吧,我又来了一个奇怪的人。

I have a running project where I'm building a tree of Controls/Components of a given form and use that to generate the shortest unique path to any one of them.我有一个正在运行的项目,我正在构建一个给定形式的控件/组件树,并使用它来生成到其中任何一个的最短唯一路径。 Just as a context for the actual question.就像实际问题的上下文一样。

Now I've had quite a bad time dealing with TabControl, which is finished quite badly on many levels, but most of it could be dealt with WinAPI calls.现在我在处理 TabControl 时遇到了很糟糕的时间,它在很多层面上都做得很糟糕,但大部分都可以通过 WinAPI 调用来处理。 Fine.美好的。 Now I have a problem which I can't figure out even when looking into the Microsoft reference codebase.现在我遇到了一个问题,即使在查看 Microsoft 参考代码库时也无法弄清楚。

TabControl for some unknown reason reorders the ControlCollection based when a tab is selected.出于某种未知原因,TabControl 会在选择选项卡时根据 ControlCollection 重新排序。 From a tiny test app, it seems far more random than I first anticipated.从一个很小的测试应用程序来看,它似乎比我最初预期的要随机得多。 It's something that's unfortunately breaking my fallback method for dealing with unnamed Controls and the stable indexing is very important to me.不幸的是,这破坏了我处理未命名控件的后备方法,稳定的索引对我来说非常重要。

using System;
using System.Windows.Forms;

namespace TabControlOrderTest
{
    using System.Threading;
    using System.Threading.Tasks;

    public partial class Form1 : Form
    {
        private TabControl tabControl1;
        private ListBox listBox1;

        public Form1()
        {
            this.tabControl1 = new TabControl();
            this.listBox1 = new ListBox();
            this.InitializeComponent();
            this.SuspendLayout();
            // 
            // tabControl1
            // 
            this.tabControl1.Location = new System.Drawing.Point(12, 12);
            this.tabControl1.Name = "tabControl1";
            this.tabControl1.SelectedIndex = 0;
            this.tabControl1.Size = new System.Drawing.Size(566, 244);
            this.tabControl1.TabIndex = 0;
            this.tabControl1.SelectedIndexChanged += new EventHandler(this.tabControl1_SelectedIndexChanged);
            // 
            // listBox1
            // 
            this.listBox1.FormattingEnabled = true;
            this.listBox1.Location = new System.Drawing.Point(658, 34);
            this.listBox1.Name = "listBox1";
            this.listBox1.Size = new System.Drawing.Size(130, 251);
            this.listBox1.TabIndex = 2;

            this.Controls.Add(this.listBox1);
            this.Controls.Add(this.tabControl1);

            this.ResumeLayout(false);


            for (var i = 0; i < 10; i++)
            {
                this.tabControl1.TabPages.Add(
                    new TabPage($"tabPage{i}")
                    {
                        Name = $"tabPage{i}"
                    });
            }
        }

        protected override void OnShown(EventArgs e)
        {
            base.OnShown(e);

            Task.Run(
                () =>
                {
                    for (var i = 9; i >= 0; i--)
                    {
                        Thread.Sleep(500);
                        this.tabControl1.SelectedIndex = i;
                    }
                });
        }

        private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
        {
            var pages = this.tabControl1.TabPages;
            var controls = this.tabControl1.Controls;
            this.Text = $"{pages.Count};{controls.Count}";
            this.listBox1.Items.Clear();
            for (int i = 0, count = this.tabControl1.TabCount; i < count; i++)
            {
                if (ReferenceEquals(pages[i], controls[i]))
                {
                    continue;

                }

                this.listBox1.Items.Add($"{pages[i].Name} != {controls[i].Name}");
            }
        }     
    }
}

Sometimes it's quite stable, sometimes it gets even more messy with every click.有时它非常稳定,有时每次点击都会变得更加混乱。 Could someone please give me a hint why is this happening?有人可以给我一个提示,为什么会发生这种情况? I would be so grateful for any clues.如果有任何线索,我将不胜感激。

EDIT: I'm asking about Controls property specifically because that's the universal place for Controls to store any underlying items.编辑:我特别询问 Controls 属性,因为这是 Controls 存储任何基础项目的通用位置。 I could switch in my production code to TabPageCollection for TabControl specifically, but it could break more things than fix so that's why I'm trying to understand the behavior.我可以将我的生产代码切换到 TabPageCollection 专门用于 TabControl,但它可能会破坏比修复更多的东西,所以这就是我试图理解这种行为的原因。

Alright, I've figured out the cause of this.好的,我已经找到了这个原因。

It's done by a Control.UpdateChildControlIndex(Control ctl) which gets called during handling WmWindowPosChanged它是由 Control.UpdateChildControlIndex(Control ctl) 完成的,它在处理 WmWindowPosChanged 期间被调用

https://referencesource.microsoft.com/System.Windows.Forms/R/13dbf65f74593e7c.html https://referencesource.microsoft.com/System.Windows.Forms/R/13dbf65f74593e7c.html

As it's obvious from the first lines, it can be optionally disabled.从第一行可以明显看出,它可以被选择性地禁用。

It's kinda a pain before .NET 4.6 (as it requires the most ugly reflection code to do it).在 .NET 4.6 之前有点痛苦(因为它需要最丑陋的反射代码才能做到)。 From 4.6+, you just call从 4.6+ 开始,您只需调用

AppContext.SetSwitch("Switch.System.Windows.Forms.AllowUpdateChildControlIndexForTabControls", false);

And profit.和利润。 Hopefully.希望。

In my case, I don't like the idea of switching some internal state of .NET FW for my Coded UI testing so I'll switch to different control collection for TabControl, as I've talk about in my question.就我而言,我不喜欢为我的编码 UI 测试切换 .NET FW 的某些内部状态的想法,因此我将切换到 TabControl 的不同控件集合,正如我在我的问题中所讨论的那样。 But it's nice to know why before I do it.但很高兴在我做之前知道为什么。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM