【问题标题】:At what point in the control life cycle does Control.Visible stop rendering?Control.Visible 在控件生命周期的什么时候停止渲染?
【发布时间】:2010-12-08 13:47:29
【问题描述】:

我正在尝试编写一个简单的实用程序 webcontrol 来显示网页内的单行消息 - 状态更新、错误消息等。这些消息将来自页面上的其他控件,通过调用 webcontrol 上的方法。如果控件在预渲染时没有任何消息,我根本不希望它在页面上渲染 - 我希望它设置 Control.Visible = false。不过,这似乎只适用于非回发渲染。这是我正在使用的代码:

public class MessageList : WebControl
{

#region inner classes

    private struct MessageItem
    {
        string Content, CssClass;

        public MessageItem(string content, string cssClass)
        {
            Content = content;
            CssClass = cssClass;
        }

        public override string ToString()
        { return "<li" + (String.IsNullOrEmpty(CssClass) ? String.Empty : " class='" + CssClass + "'") + ">" + Content + "</li>"; }
    }

    private class MessageQueue : Queue<MessageItem> { }

#endregion

#region fields, constructors, and events

    MessageQueue queue;

    public MessageList() : base(HtmlTextWriterTag.Ul)
    {
        queue = new MessageQueue();
    }

    protected override void OnLoad(EventArgs e)
    {
        this.Controls.Clear();
        base.OnLoad(e);
    }

    protected override void OnPreRender(EventArgs e)
    {
        this.Visible = (queue.Count > 0);

        if (this.Visible)
        {
            while (queue.Count > 0)
            {
                MessageItem message = queue.Dequeue();
                this.Controls.Add(new LiteralControl(message.ToString()));
            }
        }

        base.OnPreRender(e);
    }

#endregion

#region properties and methods

    public void AddMessage(string content, string cssClass)
    { queue.Enqueue(new MessageItem(content, cssClass)); }

    public void AddMessage(string content)
    { AddMessage(content, String.Empty); }

#endregion

}

我也尝试将检查放入 CreateChildControls,结果相同。

【问题讨论】:

  • 请注意,由于您没有对您的 CssClass 进行属性编码或对您的内容进行 html 编码,因此如果其他地方没有这样做,您可能容易受到注入攻击。

标签: c# asp.net


【解决方案1】:

其实我自己也想通了,我认为这个答案会对社区有用。

它看起来像一个控件,它的 Control.Visible 设置为 false 实际上在 Page_Load 事件之后的某个时间停止。这里的窍门是将 Control.Visible 属性加载到 ViewState 中。因此,如果第一个页面上没有消息,则控件将自身设置为 Visible = false,并且永远不会再到达 CreateChildControls 或 OnPreRender。

解决方案是在未跳过的较早事件之一中重置控件的可见性。以下更改解决了我的问题:

protected override void OnLoad(EventArgs e)
{
--> this.Visible = true;
    this.Controls.Clear();
    base.OnLoad(e);
}

【讨论】:

  • 我用 OnPreRender 进行了测试,但没有像你所说的那样调用事件,我从来没有想过,但我想如果控件设置为 Visible=False 那么什么都没有是有道理的渲染。
【解决方案2】:

不要修改“可见”属性,试试这个:

    protected override void Render(HtmlTextWriter writer)
    {
        if (queue.Count > 0)
            base.Render(writer);
    }

【讨论】:

  • 请注意,如果 Visible 确实设置为 false,则不会调用 Render(),因此这种方法无法使控件再次可见。只要您完全不理会 Visible,就可以了。
  • 噢,这真是太聪明了!并将可见属性留作其他用途。比我的解决方案好!
【解决方案3】:

如果您的代码必须在 PreRender 上运行,即使控件不可见(因此在 OnLoad 中设置 Visible=true 不是解决方案),您可以利用页面的 PreRender 事件将始终触发的事实。

protected void AlwaysPreRender( object sender, EventArgs e )
{
    if ( /* some condition */ )
    {
        this.Visible = true;
    }
    // else leave Visible as it was
}

protected override void OnLoad(EventArgs e)
{
    Page.PreRender += this.AlwaysPreRender;
}

这也处理了控件的父级(或其他祖先)不可见的可能性。在这种情况下,即使您确保控件本身的 Visible=true,控件的 OnPreRender 也不会触发。

【讨论】:

    【解决方案4】:

    我建议改用 OnInit:

    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
    
        this.Visible = (queue.Count > 0);
    
        if (this.Visible)
        {
            while (queue.Count > 0)
            {
                MessageItem message = queue.Dequeue();
                this.Controls.Add(new LiteralControl(message.ToString()));
            }
        }
    }
    

    【讨论】:

    • 这会发生得太早。我的消息是由其他控件在其 OnLoad 和事件方法期间添加的。如果我将此步骤放入 OnInit,我将永远不会显示任何消息。
    • 明白,我只是认为破解控制属性来触发你的事件可能很难维护。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-15
    • 1970-01-01
    • 1970-01-01
    • 2010-12-18
    • 1970-01-01
    • 2022-11-29
    • 1970-01-01
    相关资源
    最近更新 更多