TabControl переупорядочивает ControlCollection при выборе вкладки - PullRequest
0 голосов
/ 20 марта 2019

Хорошо, у меня опять странный пример.

У меня есть работающий проект, в котором я строю дерево элементов управления / компонентов заданной формы и использую его для создания кратчайшего уникального пути к любомуодин из них.Просто в качестве контекста для реального вопроса.

Теперь у меня было довольно плохое время, когда я имел дело с 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, но он мог сломать больше вещей, чем исправить, поэтому я пытаюсь понять поведение.

1 Ответ

0 голосов
/ 22 марта 2019

Хорошо, я выяснил причину этого.

Это делается с помощью 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);

и получаете прибыль.Надеюсь.

В моем случае мне не нравится идея переключения внутреннего состояния .NET FW для моего тестирования закодированного пользовательского интерфейса, поэтому я перейду к другой коллекции элементов управления для TabControl, как я уже говорило в моем вопросе.Но приятно знать почему, прежде чем я это сделаю.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...