.NET框架-Winform技術中元件被容器引用陷阱

alg-flody發表於2017-01-12

作者:vuefine
文獻: msdn library
平臺:.NET 2.0+


  .net(C#) WinForm開發,因為是視覺化設計,所以可以通過手動,直接將某個需要的元件加入到設計介面中,.net會自動將初始化這個元件,包括屬性設定等,新增到InitilizeComponent()中,並且這個元件會新增相應的父元件中。所有的這些都是.net自動完成的。

  但是,某些場景下,我們需要手寫程式碼改變元件所屬的父容器。比如某些元件原來屬於父容器A,但是我們想將這些元件調整到父容器B中,此時一個有趣的問題出現。

以下3個元件原來位於this:

            this.Controls.Add(this.operRateUC);
            this.Controls.Add(this.personProductUg);
            this.Controls.Add(this.procedingPanel);

想調整這3個元件到adjustPanel元件。如下面的程式碼所示:

     private void moveToAdjustPanel()
     {
          //AdjustablePanel是一個Control類
          AdjustablePanel adjustPanel = new AdjustablePanel();
          foreach (Control ultraControl in this.Controls)
            {
                    if (ultraControl.GetType() == typeof(UltraGrid) || 
                        ultraControl.GetType() == typeof(UltraChart) ||
                        ultraControl.GetType() == typeof(Panel))
                {
                    adjustPanel.Controls.Add(ultraControl);                    
                }  
            }
     }

  這種批量移動元件到另一個父元件的方式是失敗的。
  adjustPanel每次新新增了一個元件後,this.Controls的元件就會改變,並且未丟擲foreach迭代器被修改的異常這不知道是不是微軟的一個bug。

在bbs.csdn.net上發帖求助,回覆,大都認為foreach遍歷會報錯,但是的確編譯器未丟擲任何異常。我重新再編譯器重新做了一個簡單的測試,結果,發現foreach遍歷的確不報錯,但是得不到想要的結果。


元件移動父容器測試

測試程式碼如下,測試的預期是將2個Button元件從this中移動到groupBox1中。但是結果卻是this 中依然有button1,只有button2被移動到了groupBox1中。

奇怪點:

foreach迭代器被修改,為什麼不報錯???
為什麼只有button2移動到groupBox1中了???

        public Form1()
        {
            InitializeComponent();
            moveButtonsToGroupBox();
            //controlNames的結果為{groupBox1,button1}
            var controlNames = showAllChildControls(this); 
            //controlNamesInGroup的結果為{button2}
            var controlNamesInGroup = showAllChildControls(this.groupBox1);             
        }
        /// <summary>
        /// 移動位於Form上的按鈕到GroupBox中
        /// </summary>
        private void moveButtonsToGroupBox()
        {
            foreach(Control c in this.Controls)
            {
                if (c.GetType() == typeof(Button))
                    this.groupBox1.Controls.Add(c);
            }
        }
        /// <summary>
        /// 展示c控制元件的所有子元件的Name
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        private List<string> showAllChildControls(Control c)
        {
            if (c == null) return null;
            List<string> controlNames = new List<string>();
            foreach(Control chl in c.Controls)
            {
                controlNames.Add(chl.Name);
            }
            return controlNames;
        }

相關文章