为什么从父控件中删除控件会触发VisibilityChanged with Visible = true ?

本文关键字:控件 with VisibilityChanged Visible true 删除 为什么 | 更新日期: 2023-09-27 18:10:42

我正在处理一些遗留代码,我不能引入大的变化。有一个控件具有与OnVisibleChanged事件相关联的逻辑。

在应用程序生命周期中的某个时刻,控件将从其父控件中删除,当此情况发生时,将触发两次OnVisibileChanged事件。第一次控件可见度为false,第二次控件可见度为true

为什么会发生这种情况?为什么能见度改变是在第二次触发并且Visible为真?

复制我描述的行为的简单方法:

创建控件:

class MyButton: Button
    {
        public MyButton()
        {
            Text = "Test";
        }
        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);

            MessageBox.Show(string.Format("Im now visible {0}", Visible));
        }        
    }

在表单中使用它,并在otherButton的on click事件中删除它:

public partial class Form1 : Form
    {
        private MyButton myButton = new MyButton();
        private GroupBox myGroupBox = new GroupBox();
        private Button otherButton = new Button();
        public Form1()
        {
            InitializeComponent();
            otherButton.Text = "Remove";            
            otherButton.Click += otherButton_Click;
            this.myGroupBox.Controls.Add(myButton);
            this.Controls.Add(otherButton);
            this.Controls.Add(myGroupBox);
        }
        void otherButton_Click(object sender, EventArgs e)
        {
            myGroupBox.Controls.Remove(myButton);
        }        
    }

运行后,如果单击otherButton,消息将显示两次,第一次可见性将是false,第二次将是true

为什么从父控件中删除控件会触发VisibilityChanged with Visible = true ?

原因是在本地调用:

[DllImport("user32.dll")]
public static extern IntPtr SetParent(HandleRef hWnd, HandleRef hWndParent);

,在Control.Remove(...)方法中调用。如果将Controls.Remove(myButton);替换为SetParent(myButton.Handle, IntPtr.Zero);,则会触发相同的两个事件。

我的猜测是,当控件从其父控件中删除时,VisibleChanged事件很方便。然而,控件从未被显式隐藏。因此,第二个调用必须将Visible属性设置回true。否则,如果按钮被添加回控件,它将不可见。