【问题标题】:How to get the set/real value of the Visible property in Asp.Net如何在 Asp.Net 中获取 Visible 属性的设置/实际值
【发布时间】:2011-01-01 14:19:10
【问题描述】:

控件的 Visible 属性的 Get 递归查找树以指示控件是否将被呈现。

我需要一种方法来查看控件的“本地”可见值是什么,而不管其父控件设置为什么。即它本身是否设置为 true 或 false。

我已经看到了这个问题,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;
    }

这是一种可接受的方式吗?它工作正常,我没有遇到任何性能问题。它看起来非常脏,我毫不怀疑它可能会失败(例如,在实际渲染时)。

如果有人对此解决方案有任何想法,或者更好地找到价值的更好方法,那就太好了。

【问题讨论】:

  • 您在使用反射方式时遇到了什么问题?
  • GetState 的 GetMethod 为 System.Web.UI.Control 返回 null。

标签: c# .net asp.net web-controls


【解决方案1】:

经过一番挖掘,我生成了以下扩展方法,该方法使用反射来检索继承自 System.Web.UI.Control 的类的 Visible 标志的值:

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});
}

它使用反射在Control 对象中找到私有字段flags。该字段使用内部类型声明,因此需要更多反射来调用其索引器属性的 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

【讨论】:

  • +1 谢谢,这就是我所追求的。不过,我仍然确信一定有一种更简单的方法可以解决这个问题!
  • +1,很好的答案。您必须关注私有字段,因为在 Visible 属性上使用反射仍会调用 get 访问器,从而使您受制于其中的任何逻辑。尽管 ASP.NET 控件遍历控件树以检查可见性是非常不寻常的 - 它不需要,因为如果其 Visible 属性为 false 则不会调用其 Render 方法(这意味着任何子控件都不会自动获取呈现任一)。
  • @slugster:您说这样做非常不寻常,但是 ASP.NET 控件在调用其Visible 属性的getter 时会遍历控件树。针对Visible 属性运行我的答案中显示的测试用例,您将得到:false、false、false、true、true、false。
【解决方案2】:

您可以使用属性公开控件的可见性。这可以解决你的问题。

如果我错了,请纠正我。

【讨论】:

    【解决方案3】:

    如果有人试图让 Jørn Schou-Rode 的代码在 VB.NET 中工作,这里是适合我的代码。当我在 VB 中简单地翻译他的代码时,我得到一个“发现歧义匹配”异常,因为标志“Item”属性有 3 种风格。

    <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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多