簡體   English   中英

選擇選項卡時,TabControl 重新排序 ControlCollection

[英]TabControl reordering ControlCollection when selecting a tab

好吧,我又來了一個奇怪的人。

我有一個正在運行的項目,我正在構建一個給定形式的控件/組件樹,並使用它來生成到其中任何一個的最短唯一路徑。 就像實際問題的上下文一樣。

現在我在處理 TabControl 時遇到了很糟糕的時間,它在很多層面上都做得很糟糕,但大部分都可以通過 WinAPI 調用來處理。 美好的。 現在我遇到了一個問題,即使在查看 Microsoft 參考代碼庫時也無法弄清楚。

出於某種未知原因,TabControl 會在選擇選項卡時根據 ControlCollection 重新排序。 從一個很小的測試應用程序來看,它似乎比我最初預期的要隨機得多。 不幸的是,這破壞了我處理未命名控件的后備方法,穩定的索引對我來說非常重要。

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}");
            }
        }     
    }
}

有時它非常穩定,有時每次點擊都會變得更加混亂。 有人可以給我一個提示,為什么會發生這種情況? 如果有任何線索,我將不勝感激。

編輯:我特別詢問 Controls 屬性,因為這是 Controls 存儲任何基礎項目的通用位置。 我可以將我的生產代碼切換到 TabPageCollection 專門用於 TabControl,但它可能會破壞比修復更多的東西,所以這就是我試圖理解這種行為的原因。

好的,我已經找到了這個原因。

它是由 Control.UpdateChildControlIndex(Control ctl) 完成的,它在處理 WmWindowPosChanged 期間被調用

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

從第一行可以明顯看出,它可以被選擇性地禁用。

在 .NET 4.6 之前有點痛苦(因為它需要最丑陋的反射代碼才能做到)。 從 4.6+ 開始,您只需調用

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

和利潤。 希望。

就我而言,我不喜歡為我的編碼 UI 測試切換 .NET FW 的某些內部狀態的想法,因此我將切換到 TabControl 的不同控件集合,正如我在我的問題中所討論的那樣。 但很高興在我做之前知道為什么。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM