c# - 选择选项卡时 TabControl 重新排序 ControlCollection
问题描述
好吧,我又来了一个奇怪的。
我有一个正在运行的项目,我正在构建一个给定表单的控件/组件树,并使用它来生成到其中任何一个的最短唯一路径。就像实际问题的上下文一样。
现在我在处理 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 存储任何基础项目的通用位置。我可以将我的生产代码专门切换到 TabControl 的 TabPageCollection,但它可能会破坏比修复更多的东西,所以这就是我试图理解这种行为的原因。
解决方案
好吧,我已经弄清楚了这个问题的原因。
它由在处理 WmWindowPosChanged 期间调用的 Control.UpdateChildControlIndex(Control ctl) 完成
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 的不同控件集合,正如我在问题中所讨论的那样。但很高兴在我这样做之前知道原因。
推荐阅读
- sql-server - 如何将多个 Word 文档批量导入 SQL Server 数据库表
- docker - 节点:alpine 的最新版本,找不到 apk,因为 sbin 不在路径上
- c# - 组合框如何知道您是单击向下箭头还是文本框
- python - 无法连接到 Django 中的 mysqldb “ImportError: cannot import name 'CLIENT' from 'MySQLdb.constants' (unknown location)”
- node.js - 如何在 sequelize 中使用绑定获取原始 sql?
- javascript - datastudio,数据变化时如何移除画布?
- python - Pytests 不从本地目录收集测试
- powershell - 使用基于日期比较的 powershell 更新 SharePoint 列表字段
- plugins - 是否可以在文本鼠标悬停时为工具提示编写 notepad++ 插件?
- node.js - 通过 oauth2 使用 Node.js 对 Azure AD 进行身份验证