2010-01-05 65 views
4

控件的Visible屬性的Get of遞歸查找樹以指示是否將顯示控件。如何在Asp.Net中獲取Visible屬性的集合/實際值

我需要一種方法來查看控件的「本地」可見值是什麼,而不管其父控件設置爲什麼。即它本身是否設置爲真或假。

我看到這個問題,How to get the 「real」 value of the Visible property?它使用反射來獲得本地狀態,但是,我一直無法得到這個WebControls的工作。這也是一個相當髒的獲取價值的方法。

我想出了以下擴展方法。它的工作方式是從其父項中移除控件,檢查屬性,然後將控件放回到找到它的位置。

public static bool LocalVisible(this Control control) 
    { 
     //Get a reference to the parent 
     Control parent = control.Parent; 
     //Find where in the parent the control is. 
     int index = parent.Controls.IndexOf(control); 
     //Remove the control from the parent. 
     parent.Controls.Remove(control); 
     //Store the visible state of the control now it has no parent. 
     bool visible = control.Visible; 
     //Add the control back where it was in the parent. 
     parent.Controls.AddAt(index, control); 
     //Return the stored visible value. 
     return visible; 
    } 

這是一個可以接受的方式嗎?它工作正常,我沒有遇到任何性能問題。它看起來非常骯髒,我毫不懷疑可能會出現它可能會失敗的實例(例如,實際渲染時)。

如果有人對這個解決方案有什麼想法,或者還有更好的找到價值的方法,那就太好了。

+0

當您使用反射方法時遇到什麼問題? – slugster 2010-01-05 10:28:56

+0

GetMethod for GetState爲System.Web.UI.Control返回null。 – 2010-01-05 10:37:13

回答

3

了一下週圍挖後,我公司生產的使用反射來檢索Visible標誌的上課從System.Web.UI.Control繼承值以下的擴展方法:

public static bool LocalVisible(this Control control) 
{ 
    var flags = typeof (Control) 
     .GetField("flags", BindingFlags.Instance | BindingFlags.NonPublic) 
     .GetValue(control); 

    return ! (bool) flags.GetType() 
     .GetProperty("Item", BindingFlags.Instance | BindingFlags.NonPublic) 
     .GetValue(flags, new object[] {0x10}); 
} 

它使用反射來尋找私有字段flagsControl對象內。該字段用內部類型聲明,因此需要更多的反射來調用其索引器屬性的getter。

擴展方法上進行了測試以下標記:

<asp:Panel Visible="false" runat="server"> 
    <asp:Literal ID="litA" runat="server" /> 
    <asp:Literal ID="litB" Visible="true" runat="server" /> 
    <asp:Literal ID="litC" Visible="false" runat="server" /> 
</asp:Panel> 

<asp:Literal ID="litD" runat="server" /> 
<asp:Literal ID="litE" Visible="true" runat="server" /> 
<asp:Literal ID="litF" Visible="false" runat="server" /> 

測試結果:

litA.LocalVisible() == true 
litB.LocalVisible() == true 
litC.LocalVisible() == false 
litD.LocalVisible() == true 
litE.LocalVisible() == true 
litF.LocalVisible() == false 
+0

+1謝謝,那是我之後的反思。我仍然確定必須有一種更簡單的方法來找出這個問題! – 2010-01-05 10:55:37

+0

+1,很好的答案。你必須去追求私人領域,因爲在Visible屬性上使用反射仍然會調用get訪問器,讓你接受任何邏輯。雖然ASP.NET控件走控制樹檢查可見性是非常不尋常的,但它不需要如Render方法在Visible屬性爲false時不被調用(這意味着任何子控件都不會自動獲取呈現)。 – slugster 2010-01-05 11:29:39

+0

@slugster:你說這樣做非常不尋常,但ASP.NET控件在調用getter的'Visible'屬性時會走控制樹。運行我的答案中顯示的測試用例,對着'Visible'屬性,你將得到:false,false,false,true,true,false。 – 2010-01-05 12:42:55

0

可以公開的使用屬性控制的公開程度。這可以解決你的問題。

如果我錯了,請糾正我。

0

如果有人試圖讓JørnSchou-Rode的代碼在VB.NET中工作,這裏是適用於我的代碼。當我簡單地在VB中翻譯他的代碼時,我得到一個「發現不明確的匹配」異常,因爲有三種風格的「Item」屬性。

<Extension()> 
Public Function GetLocalVisible(ctl As Control) As Boolean 
    Dim flags As Object = GetType(Control).GetField("flags", BindingFlags.Instance Or BindingFlags.NonPublic).GetValue(ctl) 
    Dim infos As PropertyInfo() = flags.GetType().GetProperties(BindingFlags.Instance Or BindingFlags.NonPublic) 
    For Each info As PropertyInfo In infos 
     If info.Name = "Item" AndAlso info.PropertyType.Name = "Boolean" Then 
      Return Not CBool(info.GetValue(flags, New Object() {&H10})) 
     End If 
    Next 
    Return ctl.Visible 
End Function