在for,foreach语句中小心使用控件的SendToBack,BringToFront方法

在for,foreach语句中小心使用控件的SendToBack,BringToFront方法,第1张

概述 今天写了段VB。Net遍历控件方法,乍一看没有什么问题,但结果却出人意料,control集合的元素没有遍历完,并且有重复的元素。 Public Sub SetControlLableAndPropertyFromXml(ByVal parent As Control) For Each subControl As Control In parent.Contr

今天写了段VB。Net遍历控件的方法,乍一看没有什么问题,但结果却出人意料,control集合的元素没有遍历完,并且有重复的元素。

    Public Sub SetControlLableAndPropertyFromXml(ByVal parent As Control)            For Each subControl As Control In parent.Controls            If subControl.HasChildren Then                SetControlLableAndPropertyFromXml(subControl)            End If            If mShosaiConfig.ShosaiSetting.Items(subControl.name) Is nothing Then                Continue For            End If            subControl.Text = mShosaiConfig.ShosaiSetting.Items(subControl.name).LableText           Dim editCtl = subControl.Parent.Controls.Item(mShosaiConfig.ShosaiSetting.Items(subControl.name).Componame)            If Not editCtl Is nothing Then                If Not mShosaiConfig.ShosaiSetting.Items(subControl.name).Editable Is nothing Then                    editCtl.Enabled = mShosaiConfig.ShosaiSetting.Items(subControl.name).Editable                End If                            End If        Next    End Sub


我一直以为是foreach改变了读取数据的数序,或者说他可能不是按顺序读取,但用reflecter看了下,Controls是ControlConnection集合,这个集合实现了IEnumerable接口,其本质和用for语句遍历是一样的,他们都是index + 1 的方式,用索引来访问的。所以问题不在foreach语句。

最后发现是这一句editCtl.Enabled = mShosaiConfig.ShosaiSetting.Items(subControl.name).Editable出了问题。editCtl是重写过的ComBox控件,在OnEnabledChanged事件中用了,SendToBack和BringToFront方法。

    Protected OverrIDes Sub OnEnabledChanged(ByVal e As System.EventArgs)        MyBase.OnEnabledChanged(e)        If Me.Enabled Then            Me.m_lblComboText.Visible = False        Else            Me.m_lblComboText.Visible = True            Me.SendToBack()            Me.m_lblComboText.BringToFront()        End If    End Sub


罪魁祸首就是这个SendToBack和BringToFront,这两个函数的使用,可能会导致控件所在的父控件(parent)的Controls集合元素移位,也就是如果我们在for,foreach语句中,对Controls集合的元素调用了这两个方法,由于Controls的元素移动了,再按index +1 的方式来遍历可能有未遍历的元素移动到了Controls集合的前面,造成遍历不完全。同理,已经遍历的元素移动到Controls的后面会造成元素的重复。

SendToBack和BringToFront会改变控件的“Zindex“值来改变控件的显示层次,来看看他的内部实现:

public voID SendToBack(){    if (this.parent != null)    {        this.parent.Controls.SetChildindex(this,-1);    }    else if (this.IsHandleCreated && this.GettopLevel())    {        SafeNativeMethods.SetwindowPos(new HandleRef(this.window,this.Handle),NativeMethods.HWND_BottOM,3);    }}


==》

public virtual voID SetChildindex(Control child,int newIndex){    this.SetChildindexInternal(child,newIndex);}

==》

internal virtual voID SetChildindexInternal(Control child,int newIndex){    if (child == null)    {        throw new ArgumentNullException("child");    }    int childindex = this.GetChildindex(child);    if (childindex != newIndex)    {        if ((newIndex >= this.Count) || (newIndex == -1))        {            newIndex = this.Count - 1;        }        base.MoveElement(child,childindex,newIndex);        child.UpdateZOrder();        LayoutTransaction.Dolayout(this.owner,child,Propertynames.Childindex);    }}

关键就是这句base.MoveElement(child,newIndex);会造成Controls内元素的重新排列。

那么对要遍历Controls,并且要改变其中Control元素显示层次应该怎么办呢?

法一:声明一个List<Control> lstControls,先遍历controls,把这些元素加到lstControls中,再对lstControls遍历,调用SendToBack方法。这种方法主要是避开对ControlConnection集合的遍历。

法二:已经知道要遍历控件name的场合,可以用parent.Controls.Find(controlname,True)来查找,再调用SendToBack方法。

也许还有其它更好方法,有待研究。

总结

以上是内存溢出为你收集整理的在for,foreach语句中小心使用控件的SendToBack,BringToFront方法全部内容,希望文章能够帮你解决在for,foreach语句中小心使用控件的SendToBack,BringToFront方法所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/1289256.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-06-09
下一篇2022-06-09

发表评论

登录后才能评论

评论列表(0条)

    保存